苏嵌嵌入式Linux实训 第6天

嵌入式学习第六次课程,课程逐渐接近C语言学习的尾声,其中概念性的东西和编程的语法逐渐增多,需要把握大量的时间去学习,最近又面临挑战杯答辩的各项准备,实在是学有余而力不足。

1、课程内容 


主要介绍函数、内存管理、关键字、复合数据类型等相关的语法和编码

函数

函数三要素:函数名、形参、返回值
(1)函数名:命名—自注释行 动词+名词 add_user del_user 
(2)函数参数:实参是什么类型,形参就要定义成什么类型
     <传数组名>
传一维数组名,用元素的指针;
传二维数组名,用一维数组指针;
传三维数组名,用二维数组指针;
传指针数组名,用指针的指针;

(3)函数的返回值:return exit
(4)华为编码规范<人口参数检查、函数的异常处理>

内存管理

内存池:(将使用多次malloc操作改变成只使用1次)
malloc/free是一个开销非常大的操作

苏嵌嵌入式Linux实训 第6天

关键字

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给类型重命名?

一是表明该类型的特殊作用,

二是将来有可能要改变这种类型(比如提高精度)

三是简化代码,便于批量修改具体类型。