(笔试 & 面试)嵌入式C语言基础知识
把姿态放低,你会发现看不惯的人和事越来越少,琐碎的生活不再是一地鸡毛,你和世界的关系也越来越好。 —- 人民日报 《[夜读] 格局越大,姿态越低》
通过最近几家公司的笔试及面试,发现他们不仅关注你是否知道存在这个东西,同时还需要你说出这些东西是怎么高效实现以及它们之间的区别。虽然我也答出七七八八,但能够明显发现自己有些基础不牢固,细节掌握不清楚,编码能力有点弱。做技术需要踏踏实实,一步一步脚印,从小事做起,从基础积累,细节决定成败,所以就此在这总结一下最近遇到所有问题及一些基础知识。
strcpy及相关函数的实现
1 | /* |
这个函数为什么要返回char *
类型指针?
答: 林锐的《高质量C++编程指南》给出原文如下:
有时候函数可能不需要返回值,但为了增加灵活性如支持链式表达式,可以附加返回值。
例如字符串复制函数strcpy 的原型:
char *strcpy(char *dest,const char *src);
strcpy 函数将src 拷贝至输出参数sdest 中,同时函数的返回值又是dest。
这样做并非多此一举,可以获得如下灵活性:
char str[20];
int length = strlen( strcpy(str, “Hello World”) );
memcpy及相关函数的实现
1 | /* |
如果dest与src指向的内存区域有重叠,怎么实现memcpy?
答:代码如下:
1 | /* |
由于memcpy
不需要判断重叠,所以它的运行速度比memmove快,在确定dst和src不会重叠的情况下,可以使用memcpy
strcpy与memcpy区别
- 复制的内容不同,
strcpy
只能复制字符串,但memcpy
可以复制任意内容,比如字符数组、整数、浮点数、结构体等 - 复制的方法不同,
strcpy
不需要指定长度,直到它遇到被复制字符串的结束符\0
才会停止,所以容易溢出。但memcpy
则是根据其第三个参数决定复制的长度 - 用途不同,通常在复制字符串时使用
strcpy
,而需要复制其他类型数据时一般用memcpy
最大公约数(Greatest common divisor)和最小公倍数(Least Common Multiple)
欧几里德法 (辗转相除法)
1 |
|
尼考曼彻斯法(辗转相减法)
1 |
|
两者异同
- 都是求最大公因子的方法,前者以除法为主,后者以减法为主。特别当两个数相差较大时,前者运算次数较少。
- 结束条件不同,前者是当相除余数为零时,后者当减数与差相等时。
static、const和volatile
const关键字
作用:
- 给读你代码的人传达非常有用的信息,声明一个参数为常量是为了告诉用户这个参数的应用目的;
- 通过给优化器一些附加信息,添加关键字
const
可能产生更紧凑的代码; - 合理使用关键字
const
可以使编译器很自然地保护那些不希望被修改的参数,防止无意的代码修改,可以减少bug的出现。
如下声明:
1 | int const a; |
- 前两个的作用一样,a是一个常整型数
- a是一个指向常整型数的指针,整型数不可修改,指针变量可以修改
- a是一个指向整数的常指针,指针指向的整型数可以修改,但是指针变量不可以修改
- a是一个指向常整数的常指针,指针指向的整型数不可以修改,指针变量也不可以修改
应用:
- 阻止一个变量被修改,可使用
const
,在定义const变量时,需要先初始化,不然以后没有机会修改 - 修饰指针,指定指针本身为const,也可以指定指针所指的数据为const,或二者同时指定为const
- 在一个函数声明中,const修饰形参指示在函数内部不可以改变该形参值
static关键字作用
- 在函数体内,一个声明为
static
变量在该函数被调用过程中维持其值不变。注意:静态局部变量存放位置为.data段
,如果没有初始化,编译器会自动为其赋值0。 - 在编译单元内但在函数提外,一个声明为
static
变量可以被这个编译单元内所以函数访问,但不能被其他编译单元中函数访问,也就是说它是一个本地全局变量。注意:静态全局变量和普通全局变量存储位置要么.data段
要么.bss段
,这个关键字影响语法层面变量的作用域,不影响变量的生命期。 - 在编译单元中,一个声明为
static
函数只能被这个编译单元内的其它函数调用。也就是这个函数被限制在声明它的编译单元的本地范围内使用。