1.C语言和C++的区别?

2.什么是局部变量 函数参数是什么变量?
局部变量是定义在函数内部或者大括号{}代码块内部的变量,它的作用域只局限于当前这个代码块,出了大括号就无法访问。局部变量存储在栈空间,当程序进入代码块时创建,代码块执行完毕之后就会自动销毁。局部变量不会自动初始化,如果没有手动赋值,里面存放的是随机垃圾值。函数的形参属于局部变量。
实参本身不一定是某一类固定变量,要看它写在什么地方: 如果调用函数时,传入的实参是写在 main 或者其他函数内部定义的变量,那这个实参就是局部变量 ; 实参也可以直接写常量数字,比如func(10),这个10是字面量,不是变量。
3.实参和形参的关系是什么?
形参是函数定义时,写在函数括号里的参数,属于函数内部的局部变量,存储在栈上,只有函数被调用的时候才会创建,函数执行结束就销毁。
实参是调用函数时,传入括号中的数据,可以是变量、常量、表达式。实参在函数外部,用来给形参提供初始值。 值传递时,会把实参的值拷贝一份给形参,形参只是实参的副本,在函数内部修改形参,不会影响外面的实参。
4.值传递、指针传递、引用传递的区别?




5.C/C++中的内存空间分布

代码区由代码段(也就是图中的text正文)和常量区组成,所谓的代码段其实就是存放源码进行编译之后生成的能被CPU识别的机器二进制指令,这些指令会被放在代码段中,只读不能修改。


值得注意的是
对象的成员函数(包括虚函数、普通成员函数),编译后的机器指令全部放在 text 代码段(代码正文),不在对象本身里面!
通俗解释
C++ 的对象里,只存成员变量 ,不会存成员函数。 成员函数本质就是普通函数,只是多了一个隐藏参数 this指针。所有同类对象共用同一份函数代码,不需要每个对象都存一份函数。

6.讲一讲什么是预编译、编译、汇编、链接,它们的统称是什么,它们每个阶段做了什么?
预编译、编译、汇编、链接统称为编译,所以编译分为狭义上的编译和广义上的编译。这四个步骤的统称除了可以成为编译,也可以称为完整编译链路。
①预编译

②编译

③汇编

④链接

符号指函数名、全局变量名。符号表存放在目标文件中,记录所有符号名称、类型、位置信息,供链接器使用。 符号解析是链接器的工作:遍历全部目标文件的符号表,为每一个被调用的符号找到它的定义。找不到定义就报链接错误。 汇编生成的.o目标文件是二进制文件,里面存放机器指令、数据段、符号表、重定位信息。但是单个目标文件不知道外部符号的真实地址,无法直接运行,需要链接。
8.讲一讲什么是野指针?野指针本质上是怎么引起的?
什么是:
野指针就是指向一块无效、非法内存地址的指针。 这个地址不是程序合法可用的内存,对野指针解引用,会发生未定义行为,大概率程序崩溃(段错误)。
注意:野指针≠NULL 空指针。NULL 指针是明确指向 0 地址;野指针是地址是随机垃圾值,不确定。
什么会引起野指针:


9.空指针和野指针的区别
空指针是明确指向 0 地址,可以用if(p == nullptr)判断;野指针是随机无效地址,无法判断,不能简单用 if 判断。
10.讲一讲什么情况会引起段错误?
段错误(Segmentation fault,segfault)本质:访问了进程虚拟地址空间中,不允许你读写的内存地址,意思就是只能访问的应该是进程虚拟地址空间中的合法地址或者允许你进行写的地址,像常量区就是不能进行写的地址,如果你修改的话也会引起段错误,操作系统内核检测到,直接杀死程序。




11.内存泄漏和段错误的区别?什么情况会引起内存泄漏?
在堆上申请的内存,使用完毕之后没有释放,并且程序再也找不到这个内存的地址,无法释放,造成这块堆内存永久占用。
注意:内存泄漏不是内存损坏,不是程序崩溃,是内存被占用,程序运行越久,占用内存越来越大。

常见原因:new 忘记 delete、指针覆盖丢失原有地址、异常跳过释放、shared_ptr 循环引用。进程退出后操作系统会回收全部内存;长期运行的程序发生内存泄漏,会内存持续上涨,最终 OOM 崩溃。
我在开发中用的是htop或者top来观察在程序运行期间CPU是否会持续上涨。
11.什么时候使用数组什么时候使用指针?
如果需要固定大小的连续内存,内存可以在栈上自动分配,不需要手动释放,就用数组。
如果内存大小运行时才能确定,需要在堆上动态申请内存,或者需要改变指向的地址,就用指针。
数组名是常量地址,不能修改;指针是变量,可以修改指向。sizeof 数组得到数组总大小,sizeof 指针得到指针本身的字节数。
什么是常量地址和指针的区别是什么?
arr代表数组首元素的地址,这个地址是固定不变的,数组开辟在哪,arr 就永远是这个地址 。- 它不是指针变量,没有自己的存储空间,只是代表这块内存起始地址,不能修改这个地址值。
也就是说我们平常说的指针其实是指针变量,指针变量自己本身有自己的地址,而指针变量的自己的指针指向的空间中存储的是使用指针变量的对象的地址。而数组名可以代表数据首元素地址中的这个地址就是数组首元素的地址,没有多的一层需要指针变量存储的原因是,数组是开辟的一段连续的空间,我们可以通过数组首元素地址和type找到下一个数组元素的地址。
12.什么是valatile关键字?

❌ volatile 不保证原子性,不保证多线程同步,不能替代互斥锁 mutex。多线程下只用 volatile 依然会有数据竞争。
13.什么是数组指针和指针数组?

数组指针做自增运算,会一次性跳过整个数组长度,常用于二维数组。*p得到的是数组,等价数组名,也就是数组首元素的地址。
14.讲一讲什么是makefile,makefile写的过程是什么?


编写思路:先写最终可执行程序目标,依赖各个.o 目标文件;再写各个.o 目标文件,依赖对应的 cpp 源码;最后写 clean 伪目标清理产物。
15.什么是二级指针,二级指针和数组指针的关系是什么?
int **p 是二级指针, 就是说指针指向指针,指针p中存的还是指针。而数组指针 int (*p) 5,是指针里面存的是数组的首元素地址。
不管二级指针、数组指针,p 本身都是指针变量,64 位下都只占 8 字节,只能存地址,存不下完整数组!

16.讲一讲二维数组?
C++ 二维数组本质是数组里面存放一维数组,内存是一块连续空间,行优先存储。 int arr[3][5],arr 代表第一行的地址,类型是数组指针int (*)[5],arr+1 跳过一整行。 arr 0 是第 0 行首元素地址,类型 int*,arr 0+1 只跳过一个 int。 二维数组名不能赋值给二级指针 int**。 函数形参二维数组,列数必须指定,第一维可以省略,会退化为数组指针。 指针数组 int* p 3 不是二维数组,内存不连续,作为参数退化成二级指针。

17.二维数组为什么只能省略行不能省略列?为什么要省略行?

18.const修饰指针三方法?

