面试之C++(篇四:其他常见问题)

目录

1.static的作用

2.引用和指针的区别

3.malloc/free与new/delete的区别

4.内存泄漏问题及检测方式

5.预处理指令

6.宏定义#define与全局const的区别

7.简述宏函数

8.宏函数与普通函数的区别

9.遍历时用++i还是i++

10.如何判断一个程序是由C编译还是C++编译的


1.static的作用

(1)限制了修饰对象的作用域为本程序文件。外部程序文件不能访问该对象,本文件中的静态或非静态函数都可以调用静态变量和函数。

(2)使修饰的对象具备记忆功能和全局生存期,static定义的对象存储在静态存储区。

(3)类中定义的静态成员直接用类作用域调用,即 A::func()A::var。类的静态成员只能够调用该类的静态成员,不能调用非静态成员,这是因为类内非静态成员是通过指向类对象实例的this指针调用的,而静态成员没有this指针。

(4)类内声明静态成员时,不占用内存,需要在类以及main函数外进行定义,若没有显示初始化,则在第一次调用时执行初始化,默认初始化为0。

 

2.引用和指针的区别

(1)指针是一个存放地址的变量,而引用是变量的别名。从汇编实现的角度看,引用和指针都是占用内存的,引用的实现是一个指针常量,因此当引用绑定了一个对象后,不能转而绑定另外一个变量。

(2)指针在声明时可以不初始化(建议初始化),而引用在声明时必须初始化,绑定一个对象。

(3)指针是对象,而引用不是对象。因此可以定义指针的指针,不能定义引用的引用。

(4)sizeof得到的值不同 。sizeof指针得到指针所占的内存大小(32位系统为4B,64位系统为8B),sizeof引用得到的是绑定的对象所占的内存大小。

 

3.malloc/free与new/delete的区别

(1)属性不同。malloc/free是库函数,需要头文件支持;new/delete是关键字,需要编译器支持。

(2)参数不同。malloc在申请内存时需要具体指出申请的字节长度;new会自动根据类型申请相应大小的内存。

(3)返回值不同。malloc申请成功时返回void*,因此需要强制类型转换,失败则返回NULL;new申请成功时返回对象类型的指针,无需进行类型转换,失败则抛出bad_alloc异常。

(4)申请方式不同。new先调用operate new申请内存(底层使用malloc),然后调用对象类型的构造函数初始化,delete先调用对象类型的析构函数销毁对象,再调用operate delete释放内存(底层用free);而malloc/free只申请内存空间,没有初始化或是销毁对象,因此需要另外定义函数执行这部操作。

(5)重载问题。malloc/free不支持重载;new/delete支持重载。

(6)布局new不申请内存空间,仅将已分配的内存空间指定为起始内存地址。

(new申请的内存在“自由存储区”上,这个“自由存储区”是个针对new提出的抽象概念,一般是堆,但也可以改在其他内存存储区域)

 

4.内存泄漏问题及检测方式

(1)内存泄漏的情况:

  • 在定义指针时没有进行初始化,在接下来又使用了该指针;
  • new了一个指针,当不再需要时没有及时进行delete,造成内存空间浪费;
  • delete一个指针后,没有让该指针指向nullptr,当再次使用时出现野指针的情况;
  • 多个指针指向一个内存区域,当delete掉一个指针时,内存已被释放,再使用其他指针导致出错;

(2)检测方法:

  • VS中导入CRT库进行内存的检测;
  • 尽量使用STL,指针都用C++11的智能指针;

 

5.预处理指令

 

6.宏定义#define与全局const的区别

(1)编译器处理的方式不同。宏在预处理阶段进行展开,因此无法直接进行调试;const常量时在编译运行阶段处理。

(2)类型安全检查不同。宏没有类型,因此不进行类型安全检查;const修饰的对象在编译阶段执行类型安全检查。

(3)存储方式不同。宏在预处理中展开,也即是在编译前就将所有用到宏的地方进行替换,不分配内存;const修饰的对象需要分配内存。

(4)宏具有边缘效应,在展开时只是字符串的替换,可能会出现与原始语义不同的问题。

(5)宏不能作为参数传值给函数,const修饰的对象可以。

(6)宏在定义之后可以通过#undef进行销毁。

 

7.简述宏函数

(1)宏函数的格式,这里以交换两数为例,#define swap(a,b) a = a + b; b = a - b; a = a - b;

(2)宏函数的参数没有类型,因此可以传入任意类型的实参。

(3)宏函数不适用于代码量较大且频繁使用的函数,否则在进行宏展开时会造成大量的代码替换,导致生成的目标文件太大。

 

8.宏函数与普通函数的区别

(1)类型安全检查。宏函数的形参没有规定类型,不进行类型安全检查;普通函数的传参需要进行类型安全检查。

(2)时空间的开销。宏函数在预处理阶段进行宏展开,即简单的字符替换,因此会生成的目标文件较大;普通函数则在调用的时候需要申请栈空间进行现场的保护恢复,参数的压栈等操作。

(3)在执行比较复杂的功能时,宏函数的效率会比较低,因此比较适用于安全要求低,简单且频繁使用的函数;普通函数更适用于安全性有要求且更为复杂的场景。

 

9.遍历时用++i还是i++

用++i,因为i++会创建一个临时变量保存i的值,之后又进行销毁,而i只是类似计数的作用,不需要保存先前的值,因此在这种情况下++i的效率更高。

 

10.如何判断一个程序是由C编译还是C++编译的

#ifdef __cplusplus
    printf("C++\n");
#else
    printf("C\n");

 

以上内容均是个人理解总结,若有错误欢迎指出!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值