【面试篇 9】c++生成可执行文件的四个步骤、悬挂指针、define和const区别、c++定义和声明、将引用作为返回值的好处、类的四个缺省函数
目录
31. c++生成可执行文件的四个步骤
32. 什么是悬挂指针
33. 什么时候会出现悬挂指针
34. #define和const 有什么区别
35. include<> 和 include" " 的区别
36. c++的定义和声明
37. c++将引用作为返回值的好处和应该遵守的规则
38. 成员函数是通过什么来区分不同对象的成员变量的?
39. c++编译器为类提供的四个缺省函数是什么
31. c++生成可执行文件的四个步骤
- 预处理:预处理根据以字符#开头的命令,修改原来的c++程序。这个阶段主要处理#include、#define 等预处理指令,将头文件插入到程序中,并进行宏替换等操作。
- 编译:编译器将预处理后的文件作为输入,对其进行语法分析和语义分析等处理。这些处理会将代码转化成中间代码,中间代码是汇编语言。
- 汇编:汇编器将编译阶段生成的中间代码翻译成机器语言指令(01二进制),并将结果保存到目标文件中,生成符号表(记录函数、变量的名称、地址等)。
- 链接:链接器将各个目标文件以及程序所需要的库文件进行连接,生成可执行文件。连接器会解决目标文件之间的引用关系,并将他们组合成一个完整的程序。跨文件合成段表、符号表的合并和重定位
32. 什么是悬挂指针
悬挂指针,也叫野指针,是指指向非法内存地址的指针,即无法正常使用的指针。
33. 什么时候会出现悬挂指针
1. 使用未初始化的指针:在定义指针变量后没有对其进行初始化,这是出现悬挂指针最典型的情形。(定义指针时没初始化,它的值是随机的垃圾值指向内存里未知区域,随机地址解引用,可能崩溃或破坏数据)
int* p; // 未初始化,p的值不确定
// *p = 10; // 危险!随机地址解引用,可能崩溃或破坏数据
2. 指针所指的对象已经消亡:当指针指向的对象的生命周期结束后,对象已经消亡,但仍然使用该指针访问该对象,就会出现运行时错误。
3. 指针释放后未置空:指针被free或者delete释放后,没有置为NULL,此时指针指向的是“垃圾”内存。
4. 在c语言中,realloc函数(c语言标准库中用于动态内存重新分配的函数)使用不当:如果原内存后面没有足够的空间来将原有空间扩展成一个连续的新大小,realloc函数会从堆中重新找一块新内存,并把原来通过malloc函数得到的内存空间中的内容复制到这块新内存中,此时数据发生了移动,那么原指针所指向的内存空间实际上已经被释放,这样就会产生原指针的悬挂。
34. #define和const 有什么区别
define定义的常量没有类型,const定义的常量有类型的名字
编译器对其处理不同,define定义的宏在预处理阶段被替换可能有多个拷贝,const定义的变量在编译时确定值,只有一个拷贝(const 定义的常量,因为是 “有类型、有作用域的变量”,编译器会通过 编译优化、内存复用,让它在程序里尽可能只存 “一份拷贝” ,实现“共享拷贝”)。
35. include<> 和 include" " 的区别
- #include<>:用于包含系统标准头文件。编译器会在系统指定的标准头文件目录中查找要包含的头文件。例如<iostream>等。
- #include" ":通常用于包含用户自己编写的头文件。编译器会先在当前源文件所在目录查找。
36. c++的定义和声明
声明:主要是向编译器告知某个变量、函数或类型的存在,但不分配实际的存储空间或详细定义其行为。声明只是告诉编译器“有这么个东西”。
定义:不仅声明了变量、函数或类型的存在,还会为其分配存储空间(对于变量)或详细描述其行为(对于函数等)。一个变量或函数在程序中只能被定义一次。
37. c++将引用作为返回值的好处和应该遵守的规则
- 减少内存开销:在内存中不产生返回值的副本,避免了不必要的内存分配和复制操作。
- 提高效率:可以直接返回对象本身,而不需要创建临时对象,从而提高程序的运行效率。
- 支持链式操作:返回引用可以支持链式操作,使得代码更加简洁和易读。
- 流操作符重载返回值应声明为引用:为了保证连续使用流操作符(<<和>>)重载返回值时,操作的是同一个对象(c++标准库已经针对基础数据类型像int、char、string等,对operator<<进行了重载,所以可以直接进行链式输出操作)。
- +-*/ 四则运算符不能返回引用:这是因为四则运算符通常用于产生新的值。重载四则运算符时应返回值,而不是引用,返回引用相当于返回局部变量的引用,而不是直接修改操作数。
- 不能返回局部变量的引用:因为局部变量在函数返回后会被销毁,返回其引用会导致引用指向无效的内存区域,可能引发运行时错误。
- 可以返回类成员的引用,但最好是const类型:这样可以避免意外修改类成员的值,同时也能提高代码的可读性和可维护性。
38. 成员函数是通过什么来区分不同对象的成员变量的?
成员函数时通过对象的指针(this指针)来区分不同对象的成员变量的。
在类的成员函数内部,有一个隐含的指针this,它指向调用该成员函数的具体对象。当不同的对象调用同一个成员函数时,this指针就会指向各自对应的对象,从而能够准确地访问和操作该对象的成员变量,将不同对象的数据区分开来。
例如,有一个类Person,包含成员变量age,当不同的person对象调用成员函数来修改age时,this指针会明确指向具体的那个对象,使得修改的是当前对象的age而不是其他对象的。
39. c++编译器为类提供的四个缺省函数是什么
- 默认构造函数:在没有显式定义构造函数时,编译器会生成一个无参数的默认构造函数。
- 拷贝构造函数:浅拷贝,成员变量的赋值操作,不会产生新的堆区内存。
- 赋值运算符重载函数:会有浅拷贝的问题,因为也是成员变量的赋值操作。
- 析构函数:在对象销毁时执行一些清理工作。
持续更新......