C语言学习的三大难题!
提到C语言很多初学者都觉得,学到中间就进行不下去了,尤其是学到指针内存管理的部分,没写过几个野指针、没有debug过内存越界那都不叫完整的“人生”啊!
内存布局
提到c语言的内存操作方式,就绕不开指针。
指是针公认最难理解的概念,也是让很多C语言初学者选择放弃的直接原因。
软件开发/设计行业有这么一句话:没有什么是不能通过增加一个抽象层解决的。
这句话很对……但抽象层并不是免费的。这点就很少有人想过了:一旦你和什么东西之间被加上了一个抽象层,那你就一定得在每次访问它时受到某种限制、或者付出某些代价。
而对C来说,数组就是一个指向一片内存区域的指针……它并不去封装这个概念;恰恰相反,它鼓励你去了解藏在表象背后的东西。
于是乎,举例来说,在大量文本中搜索匹配某个模式的字符串(即strstr函数),如果C用3秒能搜完,其它语言再快可能也得9秒。因为每和一个字符比较,其它语言都要多两次索引越界与否的检查动作。
当然,这个好处并不是白捡到的。C语言用户因此而付出的代价,就是防不胜防的缓冲区溢出问题……
常见的指针使用错误包括但不限于:
内存分配未成功,却使用了它。
内存分配虽然成功,但是尚未初始化就引用它。
内存分配成功并且已经初始化,但操作越过了内存的边界。
忘记了释放内存,造成内存泄露。
释放了内存却继续使用它(所谓的野指针)。一般情况下,释放掉指针后将指针置为空。
(以上错误你中了几条?)
指针函数、函数指针听起来是不是有点像绕口令?
函数指针
C语言中指针不仅可以指向内存地址,同样也可以指向函数。指向函数的指针称为函数指针。
函数指针指向被调用函数的首地址,可以通过它来调用函数。
其定义方式为 类型说明符 (*变量名)(形参列表);其中形参列表中可以省略形参名称。
指针函数
定义函数时需要说明函数的返回值类型,其可以是整型,字符型或者是指针等,当函数的返回值为指针时,该函数就称为指针函数。
指针函数返回的是指针,其定义方式为:类型说明符 * 函数名(形参列表){函数体}
一句话总结!!!
指向函数的指针叫函数指针
返回值为指针的函数称为指针函数
一个是指针,一个是函数,你说差别大不大。
函数指针的一个应用实例:
#include <stdio.h>
// 函数指针的应用
// 计算两个整数的和
int sum(int a,int b)
{
return a + b;
}
// 计算两个整数的差
int sub(int a,int b)
{
return a - b;
}
// 计算两个整数的乘积
int mul(int a,int b)
{
return a*b;
}
// 计算两个整数相除的余
int mod(int a,int b)
{
return a%b;
}
int main(int argc, char* argv[])
{
int a = 10,b = 2;
int (*p)(int ,int ); //定义一个函数指针 根据不同的情况指向不同的函数
int op = 2;
switch(op)
{
case 1:
p = sum;
break;
case 2:
p = sub;
break;
case 3:
p = mul;
break;
case 4:
p = mod;
break;
default:
break;
}
int result = p(a,b);
printf("result = %dn",result);
return 0;
}
指针函数的一个应用实例:
//定义一个指针函数
int * getMax(int a ,int b)
{
return a > b? &a:&b;
}
int main(int argc, const char * argv[]) {
int num1 = 100,num2 =200;
int *p = getMax(num1,num2);
printf("较大的数值是:%dn",*p);
return 0;
}
结构体
很多大学开c语言课的都把结构体放在最后讲,弄得很多学生觉得结构体不重要,如果只是应付学校的考试,或者就是为了混个毕业证,的确学的意义不大。
但是如果你从事编程这个行业,结构体的概念可以说是相当重要。
没有一个业务体是完全使用原生数据类型来完成的,很多大牛在写代码解决问题的时候,首先要做的就是设计结构体。然后设计函数功能,最后才是编程实现。
如果从节省空间考虑结构体里面的数据放的顺序不一样在内存中占用的空间也不一样,结构体与结构体之间赋值,结构体存在指针那么赋值要特别注意,需要进行深度的赋值。
攻克了c语言学习的这三座大山,再去学习别的内容就相对比较简单了。
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 如何利用SNMP实现网络攻击缓解?
- winform总结5> winform程序开发注意事项
- mvc文件上传支持批量上传,拖拽以及预览,文件内容校验
- .net Core 1.0.1 下的Web框架的的搭建过程step by step
- 蓝牙芯片----BK34341开发笔记------快速入门(2)
- .net core版 文件上传/ 支持批量上传,拖拽以及预览,bootstrap fileinput上传文件
- 蓝牙芯片----BK3431开发笔记------基本外部驱动应用(3)
- .net core 利用中间件处理常见的网站功能 包括 session、routers、重定向、重写和文件下载
- 蓝牙芯片----BK3431开发笔记------RW stack中添加自定义服务教程(4)
- 图像简单处理
- 蓝牙---BLE GATT介绍
- Access数据库密码破解 C#
- 没啥用,更换注册表信息使webbrower选择适合的版本
- linux下分割和合并压缩包
- 编译.net .net Core程序 代码,仅做备份