笔者最近在找工作,因此对应聘C/C++嵌入式开发工程师容易被问到,或者经常搞不清楚的问题做一个汇总,也希望能对找工作的小伙伴起到帮助参考的作用。本篇集中于C语言方面的面试题目。
因为是自己总结的,可能会存在错误,还烦请各位读者批评指正。
①栈区 —— 局部变量 —— 向低地址生长 —— 自动释放 —— 其操作方式类似于数据结构中的栈。
②堆区 —— 向高地址生长 —— 手动分配、释放的存储区 —— malloc,free —— 它与数据结构中的堆是两回事,分配方式倒是类似于链表
③全局/静态存储区static —— 全局变量,静态变量,程序运行结束后自动释放
④常量存储区const —— 常量字符串储存在这里。储存在常量区的只读不可写。程序运行结束后自动释放
⑤代码区 —— 存放函数体的二进制代码。
——> const修饰的全局变量也储存在常量区;
——> const修饰的局部变量依然在栈上。
①栈:局部变量,函数调用传参的过程。
②堆:动态存储区,需要程序员去申请释放
③数据段(data段):显式初始化仅非零的全局变量
(1)static修饰局部变量(静态局部变量)与普通局部变量相比:
① 静态局部变量作用域与连接属性,和普通局部变量一样
② 存储类:静态局部变量分配在data/bss段,普通局部变量在栈上
③ 生命周期:因为存储类的不同,静态局部变量生命周期变长了,直到程序结束
——所以当静态局部变量离开作用域后,并没有销毁,而是仍然驻留在内存当中,只不过我们不能够再对它进行访问,直到该函数被再次调用,并且值不变。
(2)static修饰的全局变量or函数与普通的相比:
① 存储类、生命周期、作用域都一样
static修饰的全局变量的连接属性是内连接,普通的是外连接
即:static修饰的全局变量不能给文件调用——这也是静态变量和全局变量的区别。
对于局部变量来说,声明存储类型的作用是指定变量存储的区域(静态存储区或动态存储区)以及由此产生的生存期的问题
对于全局变量来说,由于都是在编译时分配内存,都存放在静态存储区,声明存储类型的作用是变量作用域的扩展问题。
1. 变量类型:是对数据分配存储单元的安排,包括存储单元的长度,及数据的存储形式
2. 内部函数:只能被本文件中的其他函数调用。定义内部函数时,在函数名、函数类型前加static。
外部函数:可供其他文件调用。定义外部函数时,在函数首部左端加上extern。若定义函数时省略extern,则默认为外部函数。
3. 因为A、B、C是外部变量
所以调用max函数时用不到参数传递,即在max函数中可以直接使用外部变量A、B、C的值
(这一点与局部变量有个实参传给形参的过程不同)
栈(操作系统):由操作系统(编译器)自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
堆(操作系统): 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收,分配方式倒是类似于链表。
栈使用的是一级缓存, 它们通常都是被调用时处于存储空间中,调用完毕立即释放。
堆则是存放在二级缓存中,生命周期由虚拟机的垃圾回收算法来决定(并不是一旦成为孤儿对象就能被回收)。所以调用这些对象的速度要相对来得低一些。
堆(数据结构):堆可以被看成是一棵树,如:堆排序。
栈(数据结构):一种先进后出的数据结构。
1. 串值的存储空间可在程序执行过程中动态分配而得。
2. 根结点是没有双亲的,所以我们约定根结点的位置域为-1.
3. 链表翻转(迭代法)
cur = tmp;//把之前下一个的值给当前位置
1. *
在不同的场景下有不同的作用:
*
可以用在指针变量的定义中,表明这是一个指针变量,以和普通变量区分开;
*
也可以在使用指针变量时,在变量前面加上,表示获取指针指向的数据,或者说表示的是指针指向的数据本身。
意义完全不同。以下面的语句为
第1行代码中*
用来指明 p 是一个指针变量,第2行代码中*
用来获取指针指向的数据。
需要注意的是,给指针变量本身赋值时不能加*
。修改上面的语句:
第2行代码中的 p 前面就不能加*
。
指针变量也可以出现在普通变量能出现的任何表达式中,例如:
py = px; //把一个指针的值赋给另一个指针2. 如果已执行“p=&a;”,即指针变量p指向了整型变量a,则:
其作用是:以整数形式输出指针变量p所指向的变量的值,即变量a的值。
3. 当数组作为函数的参数传递时,数组就自动退化为同类型指针。
1.数据类型:const修饰的变量有明确的类型,而宏没有明确的数据类型
2.安全方面:const修饰的变量会被编译器检查,而宏没有安全检查
3.内存分配:const修饰的变量只会在第一次赋值时分配内存,而宏是直接替换,每次替换后的变量都会分配内存
4.作用场所:const修饰的变量作用在编译、运行的过程中,而宏作用在预编译中
5.代码调试:const方便调试,而宏在预编译中进行所以没有办法进行调试。
—— const关键字的作用:
1. const 是定义只读变量的关键字,或者说 const 是定义常变量的关键字。
说 const 定义的是变量,但又相当于常量;说它定义的是常量,但又有变量的属性,所以叫常变量。用 const 定义常变量的方法很简单,就在通常定义变量时前面加 const 即可,如:
const 和变量类型 int 可以互换位置,二者是等价的,即上条语句等价于:
那么用 const 修饰后和未修饰前有什么区别呢?它们不都等于 10 吗?、
上面定义了两个指针p1和p2。
在定义1中const限定的是*p1,即其指向空间的值不可改变,若改变其指向空间的值如*p1=20,则程序会报错;但p1的值是可以改变的,对p1重新赋值如p1=&k是没有任何问题的。
在定义2中const限定的是指针p2,若改变p2的值如p2=&k,程序将会报错;但*p2,即其所指向的值可以改变,如*p2=80是没有问题的,程序正常执行。
const常量会在内存中分配??
三种参数传递的方式:传值、传指针、传引用
形参的存储空间是函数被调用时才分配的
引用一旦与某个对象绑定后就不再改变了
进程:是执行中一段程序,即一旦程序被载入到内存中并准备执行,它就是一个进程。进程是表示资源分配的的基本概念,又是调度运行的基本单位,是系统中的并发执行的单位。
线程:单个进程中执行中每个任务就是一个线程。线程是进程中执行运算的最小单位。
一个线程只能属于一个进程,但是一个进程可以拥有多个线程。多线程处理就是允许一个进程中在同一时刻执行多个任务。
#include :到保存系统标准头文件的位置查找头文件。
#include" ":查找当前目录是否有指定名称的头文件,然后再从标准头文件目录中查找。
每个递归必须至少有一个条件,其满足时递归便不再运行,即:此时不再引用自身,而是返回值退出。
2. 一个int占4个字节,sizeof就是4。在32位系统上,对任意指针求sizeof得到的结果都是4.??
7.2是指:宽度占7个,精确到小数点后两位(输出数据占7列,其中小数占2列)
1.左边界:只需要考虑相邻右元素是否存在坑
2.右边界:只需要考虑相邻左元素是否存在坑
3.中间:考虑相邻两边元素是否存在坑