1. C和C++的区别
1. C面向过程,C++面向对象,所以C++具有封装、继承、多态三大特性;(多态的基础是封装和继承,即通过虚函数继承父类的方法,实现接口的重复调用)
2. C++可以用STL标准库,包含vector、map、set、文件输入输出等;
3. C++中存在命名空间的概念,支持运算符重载,支持异常处理(增加程序的可靠性和容错性)。
2. 数组和指针的区别
1.数组名本质上是指向数组首个元素的指针,指针就是指向对象的地址;
2.数组名一般不能修改,指针可以修改而指向其他对象;
3.数组名的大小一般是数组元素的个数x单个元素的大小,指针大小和系统有关,32位系统一般是4字节,64位系统一般是8字节。
3. 引用和指针的区别
1.是别名,没有内存分配;指针是地址,需要分配内存保存;
2.引用在创建的时候已经构建完成,指针可以先创建后赋值;
3.有多级指针(指向指针的指针),但是没有多级引用;
4.引用和指针的自增运算结果不同;
5.常引用,const int &b = a,b不能修改,但是a可以。
4. 内联函数inline和普通函数之间的区别
内联函数在编译时直接编译到主函数中,不存在函数调用的开销;普通函数在函数调用时需要进行函数栈的出栈和入栈操作。因此对于本身比较简单且调用次数很多的函数,可以采用内联函数的形式。
5. 常量指针const int* p和指针常量int* const p之间的区别
常量指针,const int* p 是指向常量的指针,不能改变常量的值,但是指向常量的指针(地址)可以修改;
指针常量,int * const p 地址不可以修改,但是值可以修改。
6. 如何避免野指针
1.使用前初始化;
2.使用后及时释放;
3.不重复释放指针;
4.不使用悬空指针(超出作用域或者已经删除的指针)。
7. 堆heap和栈stack的区别
1.内存分配方式不同,堆通常是程序员手动分配和释放的,常用于程序中需要动态分配的内容,如动态数组等;栈通常由程序自动创建和释放,通常用于存放临时变量;
2.内存管理方式不同,堆通常是由程序员分配和释放;栈遵循后进先出原则,由系统自动完成;
3.内存大小,堆相对比较大,栈相对比较小,通常只有几百KB到几MB的大小;
4.访问速度,堆需要考虑多线程并发时的同步与互斥问题,速度相对较慢,栈由系统自动分配与释放,访问相对较快;
5.应用场景,堆适用于动态数组等需要动态分配与管理的数据结构,栈适用于临时变量与函数的存储与管理;
6.静态存储区,全局变量存放在静态存储区,在程序开始执行时给全局变量分配存储区,程序行完毕就释放。
8.关键词extern的作用
1.共享全局变量,如a.cpp中定义int golbal = 1,在b.cpp中通过extern int golbal调用;
2.相对于include头文件的方式,extern通常可以提升编译速度,因为不需要额外编译除当前extern的函数之外的无关函数;
3.extern “C” 既可以修饰一句 C++ 代码,也可以修饰一段 C++ 代码,它的功能是让编译器以处理 C 语言代码的方式来处理修饰的 C++ 代码;extern和extern “C”毫无关系。
9.减少内存泄漏的方法
1.malloc和free,new和delete要对应;
2.注意指针指向对象的大小,避免指针越界,如数组;
3.动态分配内存的指针最好不要二次赋值;
4.对指针赋值时注意被赋值指针需要不需要释放;
5.在C++中优先考虑使用智能指针。
10.malloc free和new delete之间的区别
1.malloc free是C语言的,malloc需要指定内存的大小;new delete是C++的,new不需要指定大小;
2.malloc只负责分配内存并返回内存的首地址,不会初始化;new在分配内存空间后同时完成初始化;
3.malloc返回的是void,需要进行强制类型转换,new返回目标对象的指针;
4.malloc失败时会返回NULL,需要手动释放,new失败时会抛出异常;
5.free是直接释放内存块,delete是调用析构函数进行内存释放;
6.delete和delete[]的区别,delete只调用一次析构函数,delete[]调用每个对象的析构函数。
11.RAII
RAII(Resource Acquisition Is Initialization,资源获取即初始化)机制是一种对资源申请、释放这种成对的操作的封装是通过这种方式实现在局部作用域内申请资源然后销毁资源。
12.volatile的作用
volatile和const相反,表示不稳定的,每次使用改变量,需要从内存中重新读取,在多线程都要用到同一个变量,且该变量会被改变时,经常用到。
13.switch
参数类型不能是实型,即float和double。
14.SendMessage和PostMessage之间的区别
SendMessage是阻塞的,等消息被处理后,代码才能走到SendMessage的下一行。PostMessage是非阻塞的,不管消息是否已被处理,代码马上走到PostMessage的下一行。
15.CMemoryState
查看内存使用情况,解决内存泄漏的问题。
16.char, int, float, double的大小
在32位系统中,char 1字节,short 2字节,int 4字节,float 4字节,double 8字节。
17.strcpy()和memcpy()的区别
都可以用来拷贝字符串,strcpy以‘\0’结尾,memcpy需要指定长度。
18.static
1.函数体内的static变量,只分配一次内存,所以在下一次调用时,仍然保持当前的值;
2.模块内的static变量或者函数,只能在模块内被调用;
3.类的static变量,不同对象共享一份;
4.类的static函数,可以被类的其他成员函数调用,但只能调用static成员,因为static函数只存在一份,无法使用this指针。
5.static函数和普通函数的区别,static函数在内存中只有一份内存,普通函数在每一次调用中都分别有一次拷贝。
19.const
1.变量或者指针不能被修改;
2.类的函数用const修饰,表示该函数是常函数,不能修改类的成员变量。
20.函数指针和指针函数
1.函数指针,指的是指向函数的指针;
2.指针函数,值得是返回指针的函数。
21.struct和union
union中所有成员公用一个内存,struct中每个成员都有独立的内存空间。
22.ASSERT
程序调试中常用的宏,如果值为FALSE(0),则程序报告错误并终止,否则程序继续正常执行。
23.memcpy如何提升效率
neon。
24.define和typedef
define宏定义是直接替换,在编译之前完成,没有检测过程;typedef是类型别名,在编译时完成,会进行检测。
25.sizeof和strlen
1.sizeof包含’\0’,strlen不包含’\0’;
2.sizeof在编译时已经执行,strlen本质是函数,在运行时执行。
26.头文件重复包含
1.#progma once;
2.#ifndef #define #endif。
1. 基类的析构函数为什么要定义为虚函数
如果基类的析构函数不是虚函数,那么通过基类的指针删除派生类的对象时,无法正确调用派生类的析构函数,无法正确析构对象,导致内存泄漏和其他未定义行为。
构造函数不能是虚函数,虚函数需要通过虚函数表进行查找,如果构造函数为虚函数,没有构造对象之前,没有虚函数表,相互矛盾。
纯虚函数,一般是基类中的函数没有实现,是空函数;
抽象类,有纯虚函数的类就是抽象类,不能被实例化;
重载,构造函数可以被重载,但是析构函数不可以。
2. 构造函数的调用顺序
基类的构造函数->初始化成员变量->派生类的构造函数。
3. overload(重载)、overwrite(重定义)、override(覆盖)之间的区别
1.overload重载,即函数名相同,参数类型或者参数数量不同。特例:a.只有返回值不同的两个函数不属于overload重载,如int f(int a)和float f(int a);b.const函数与原函数属于重载函数,如inf f(int a)和int f(int a) const。
2. override覆盖,虚函数继承,基类函数以关键词virtual修饰;
3. overwrite重定义,在函数继承中用到,重定义基类的函数。
overload、override、overwrite总结
4.拷贝构造函数/复制构造函数
1.拷贝构造函数的参数必须是应用,否则就会无线循环调用;
2.默认的拷贝构造函数是浅拷贝;
3.拷贝构造函数在a.类对象初始化另一个对象;b.函数参数是类的对象;c.函数返回值是类的对象时调用。
浅拷贝与深拷贝:浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存;深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。
拷贝构造(深拷贝、浅拷贝)
5.静态成员变量
静态成员变量占有自己独立的空间不为某个对象所私有,可以实现对象间的数据共享。
6.回调函数
1.所谓的回调函数,就是预先在系统的对函数进行注册,让系统知道这个函数的存在,以后,当某个事件发生时,再调用这个函数对事件进行响应;
2.类的成员函数为回调函数,就是在前面加上callback,实现和普通函数没有区别。
7.虚函数的调用
含有虚函数的类都有一个虚函数表,每个对象都有一个指向虚函数表的虚函数指针,通过指针来调用虚函数,所以虚函数占据的空间就是虚函数表指针的大小。
8.enum和enum class
enum:枚举值的名称在相同作用域下是可见的,可能会导致名称冲突;enum class:枚举值的名称在枚举类的作用域内是局部的,不会与其他作用域中的名称冲突
1. auto和decltype
如果基类的析构函
2. 智能指针
如果基类的析构函
1. UDP和TCP
1.TCP是基于连接的传输,稳定可靠;UDP是基于无连接的传输,传输速度快,但是可能会产生丢包;
2.TCP三次握手,a.客户端发送同步请求syn,b.服务端同意请求,发送syn+ack,c.客户端接收到syn+ack,回复ack;三次握手能避免由于网络感染,a中syn多次发送带来的服务端和客户端,对建立链接数量不一致的问题;
3.TCP四次挥手,客户端和服务端,都可以发起断开请求;
常用的两个网络协议——TCP和UDP
2. std::array与C++数组
1.std::array是STL的数组,头文件array,不能改变数组的大小(能改变大小的是vector),定义时必须指定大小,且不能添加或者删除元素;
2.支持快速随机访问,效率与数组相同;
3.支持迭代器访问,能获得capacity等参数(这些传统数组不支持)。
C++11: 尽量使用std::array来代替数组
3. vector中resize和reverse之间的区别
1.resize即分配空间,也创建对象,reverse只分配空间,不创建对象;
2.resize即修改size,也修改capacity,reverse只修改capacity,不修改size;
3.vector底层实现为数组。
reserve resize区别
4. deque
1.double end queue,两头的插入和删除效率高,中间的插入和删除效率低,是list和vector的中庸版本;
2.deque在底层实现中,通过数组指针(指向数组的指针)实现,分配的内存空间并不一定连续
5. map和unorderedMap
1.map底层是红黑树,占用空间相对较大,查询性能慢但是相对稳定,unorderedMap底层是哈希表,查询平均性能较高但是稳定性较差;
2.map是有序的,unorderedMap是无序的。
参考文献:
C++面试必备:常见C++面试题汇总及详细解析
C++经典面试题100例及答案
C++基础面试题汇总
100份面经c/c++校招、社招面试题总结