苏嵌嵌入式Linux实训 第6天
嵌入式学习第六次课程,课程逐渐接近C语言学习的尾声,其中概念性的东西和编程的语法逐渐增多,需要把握大量的时间去学习,最近又面临挑战杯答辩的各项准备,实在是学有余而力不足。
1、课程内容
主要介绍函数、内存管理、关键字、复合数据类型等相关的语法和编码
函数
函数三要素:函数名、形参、返回值
(1)函数名:命名—自注释行 动词+名词 add_user del_user
(2)函数参数:实参是什么类型,形参就要定义成什么类型
<传数组名>
传一维数组名,用元素的指针;
传二维数组名,用一维数组指针;
传三维数组名,用二维数组指针;
传指针数组名,用指针的指针;
(3)函数的返回值:return exit
(4)华为编码规范<人口参数检查、函数的异常处理>
内存管理
内存池:(将使用多次malloc操作改变成只使用1次)
malloc/free是一个开销非常大的操作
关键字
register
作用:尽可能的将数据保存到CPU的寄存器中,提高程序的执行效率(省去了CPU通过总线从内存中抓取数据的时间)
static
//static修饰局部变量:延长了局部变量的生命周期,程序结束之后再释放(只执行一次)
//static修饰全局变量:静态全局变量,该变量不能再其他文件中访问
//static修饰函数:该函数只能被本文件的函数调用,不能被其他文件访问
extern
//extern:外部声明:告诉编译器这个函数或者变量在其他文件定义的
const
//const:修饰变量,该变量成为一个只读变量(值是可以改变的)
//const使用注意事项:修饰某个变量时,一定要初始化
typedef
复合数据类型
struct、union、enum
//大端字节序、小端字节序
//当项目中需要多个整数宏时,就需要使用enum
2、问题解答
- 传地址和传值:什么时候传地址,什么时候传值?
当只使用不修改实参变量的值,传实参变量名;func(实参变量名)
当使用及修改实参变量的值,传实参变量的地址;func(&实参变量名)
- 传入参数、传出参数<如何让函数返回多个值?>
传入参数:就是数值的传递。在函数中不会修改这个参数,不会修改调用这个函数的函数的值。
传出参数:一般传递的是地址。
一个函数如何返回多个值:就是利用传出参数,来记载返回值。返回一个数组。返回一个结构体。
- 函数指针
//函数指针变量:保存函数的入口地址
//函数名作用:指针常量,保存函数的入口地址(函数地址)
//函数指针的作用:做函数形参,实现回调函数
//统一的调研形式:传递不同的函数,指向不同操作——多态:代码扩展性
- C语言常见的内存错误?
类型 1:内存未分配成功,却使用了它。
方 法:在使用之前检查指针是否为NULL。
1)当指针p是函数的参数时,在函数入口处用语句assert(p!=NULL)进行断言检查。
2)当使用malloc或new来申请内存时,应该用if(p != NULL)进行防错检查。
类型 2:引用了尚未初始化的指针
原 因:内存的缺省初始值究竟是什么并没有统一的标准,在使用之前都进行初始化。
1)没有初始化的观念。
2)内存的缺省值是未定义,即垃圾值。
类型 3:越界操作内存
原 因:内存分配成功且初始了,但越界操作是不允许的。
例 如:在使用数组时经常发生下标“多1”或“少1”,特别是在for循环语句时。
类型 4:忘记释放内存,造成内存泄漏。
原 因:含有这种类型错误的函数,每被调用一次,就丢失一块内存。当内存充足时看不到这种错误带来的影响,当内存耗尽时系统提示:“内存耗尽”。因此,动态内存的申请与释放必须配对,程序中malloc与free的使用次数要相同。
类型 5:释放了内存却继续使用它
原 因:对应的情况有2种
1)返回了“栈内存的指针或引用”,因为堆栈中的变量在函数结束后自动销毁。
2)某块内存被free后,没有将指向该内存的指针设置为NULL,导致产生“野指针”。
使用规则( 保证代码的健壮和安全)
规则1:使用malloc申请的内存时,必须要立即检查相对应的指针是否为NULL。
规则2:初始化数组和动态内存。
规则3:避免数组或指针下标越界。
规则4:动态内存的申请和释放必须相配对,防止内存泄漏。
规则5:free释放某块内存之后,要立即将指针设置为NULL,防止产生野指针。
- CPU的三大组成
运算器、控制器、储存器(寄存器)
3、作业解答
作业一:free时如何知道释放了多大空间?
使用malloc分配内存时候根据参数指定的大小,分配一块内存,然后返回这块内存的起始位置给调用者,这就是调用者拿到的所谓的指针。起始这个指针并不是真正的起始位置,真正的指针在malloc返回指针 p 的前面,内存分配器在 p 的前面用两个字节的空间来存放分配的内存大小信息。
作业二:static在什么情况下使用?
(1)设置变量的存储域,函数体内static变量的作用范围为该函数体,不同于auto变量,该变量的内存只被分配一次,因此其值在下次调用时仍维持上次的值;
(2)限制变量的作用域,在模块内的static全局变量可以被模块内所用函数访问,但不能被模块外其它函数访问;
(3)限制函数的作用域,在模块内的static函数只可被这一模块内的其它函数调用,这个函数的使用范围被限制在声明它的模块内;
(4)在类中的static成员变量意味着它为该类的所有实例所共享,也就是说当某个类的实例修改了该静态成员变量,其修改值为该类的其它所有实例所见;
(5)在类中的static成员函数属于整个类所拥有,这个函数不接收this指针,因而只能访问类的static成员变量。
作业三:为什么要使用typedef给类型重命名?
一是表明该类型的特殊作用,
二是将来有可能要改变这种类型(比如提高精度)
三是简化代码,便于批量修改具体类型。