嵌入式软件
一、C语言
1.1、局部变量能否和全局变量重名
能,局部会屏蔽全局
1.2、如何用C编写死循环
while (1){
} 或者 for ( ; ; )
1.3、new和malloc
1)、new和delete是C++的关键字,不需要头文件,需要编译器支持;malloc和free是C/C++的库函数,需要带头文件stdlib.h
2)、使用new操作符申请内存分配时,无需制定内存块的大小,编译器会根据类型信息自行计算;而malloc则需要支持本地所分配的大小。
1.4、static的用法(定义和用途)
static限制作用域
在C语言中,关键字static有三个明显的作用:
1)、用static修饰局部变量:使其变为静态存储方式,那么这个局部变量执行完成时不会被释放,继续保留在内存中。
2)、用static修饰全局变量:使其在本文件内部有效,而其他文件不可以被引用或链接该变量。
3)、用static修饰函数:使函数只在本文件内部有效,对其他文件不可见,这样的函数又叫静态函数;使用静态函数的好处,不用担心与其他文件的同名函数产生干扰,也是对函数本身保护的一种机制。
1.5、const的用法(定义与用途)
const主要用来修饰变量、函数形参和类成员函数:
1)、用const修饰常量:定义时就初始化,以后不能修改。
2)、用const修饰形参:func (const int a) {} 该函数在函数内不能改变。
3)、用const修饰成员函数:该函数对成员变量只能进行只读操作,就是不能修改成员变量的数值。
下面声明都是什么意思?
const int a;
int const a;
const int *a;
int *const a;
int const * a const;
第一个和第一个作用是一样的,a是常整型数。
第三个意味着a是一个指向整型数的指针。(整型数不可修改,但指针可以)
第四个意思是a是一个指向整型数的常数的指针。(指针指向的整型数是可以修改的,但指针是不可修改的)
第五个意味着a是一个指向整型数的常指针。(指针指向的整型数是不可修改的,同时指针也是不可修改的)
结论和记忆方法:
(1) const在*前面,就表示const作用于p所指向的量。所以这时候p所指向的是个常量。
(2) const在*后面,表示p本身是常量,但是p指向的不一定是常量。
(3) *在const中间,表示p本身是常量,p指向的也是个常量。
1.6、const常量和#define的区别(编译阶段、安全性、内存占用等)
用#define max 100; 定义的常量没有类型(不进行类型安全检查,可能会出现意想不到的错误),所给出的是一个立即数,编译器只是把所定义的常量值与所在的常量名字联系起来,define所定义的宏变量在预处理阶段的时候进行替换,在程序中使用到该常量的地方都要进行拷贝替换。
用const int max = 255; 定义的常量有类型(编译时会进行类型检查)名字,存储在静态区域中,在编译时确定其值。在程序运行过程中const变量只有一个拷贝,而#define所定义的宏变量却又多个拷贝,所以宏定义在程序运行过程中所消耗的内存比const变量的大很多。
1.7、volatile作用和用法
一个定义为volatile的变量是说这变量可能被意想不到的改变,这样不会假设这个变量的值了。
以下几种情况都会用到volatile:
1)、并行设备的硬件存储器。
2)、一个中断服务子程序会访问到的非自动变量。
3)、多线程应用中被几个任务共享的变量。
1.8、变量的作用域(全局变量和局部变量)
全局变量:
在所有函数体外部定义,程序所在的部分(甚至其他文件中的代码)都可以使用。
全局变量不受作用域的影响(也就是全局变量的生命周期一直到程序的结束)。
局部变量:
出现在一个作用域内,它们是局限于一个函数的。
局部变量经常被称为自动变量,它们进入作用域时自动生成,离开作用域时自动消失。
关键字auto可以显示说明这个问题,但是局部变量默认为auto,所以没有必要声明auto。
局部变量可以和全局变量重名,在局部变量作用域范围内,全局变量失效,采用的是局部变量的值。
1.9、sizeof与strlen(字符串,数组)
1)、如果是数组:
#include <stdio.h>
int main()
{
int a[5] = {
1, 2, 3, 4, 5};
printf("sizeof 数组名 = % d\n", sizeof(a));
printf("sizeof *数组名 = % d\n", sizeof(*a));
}
运行结果:
sizeof 数组名=20
sizeof *数组名=4
2)、如果是指针,sizeof只会检测到指针的类型,指针都是占用4字节的空间(32位机器)。
sizeof是什么? 是一个操作符,也是关键字,就不是一个函数,这和strlen()不同,strlen()是一个函数。
1.10、与或非,异或。运算符优先级
1.11、递归函数与回调函数的区别是什么?
答:回调是一个函数把非当前函数当做参数传递到自身内部来调用;而递归是自己调用自己。
1.12、为什么要用回调函数呢?
答:我们对回调函数的使用无非是对函数指针的应用,函数指针的概念本身很简单,但是把函数指针应用于回调函数就体现了一种解决问题的策略,一种设计系统的思想。
1.13、系统调用和函数调用的区别
系统调用是最底层的应用,是面向硬件的。而库函数的调用是面向开发的,相当于应用程序的API(即预先定义好的函数)接口。
1.14、段错误发生的原因
段错误:是指访问的内存超过了系统给程序分配的内存空间
原因:
访问不存在的内存空间
访问只读的内存空间
访问系统保护的内存空间
栈溢出
1.15、什么时候会造成内存泄漏
常见的内存泄漏
(1)内存分配未成功,却使用了它
(2)内存分配成功,但尚未初始化就引用它
(3)内存分配成功且初始化,但操作越过了内存的边界
(4)忘记释放内存,造成内存泄漏
(5)释放了内存却继续使用它