【滚动更新】C++ 八股文选集(没代码,纯应试)
1,变量的声明和定义有什么区别。
声明不分配内存,定义分配内存。变量只能被定义一次,但可以被声明多次。
// 定义 int i; // 声明 extern int i; // 定义(对资源进行了初始化) extern int i = 1;
2,#ifdef、#else、#endif和#ifndef的作用。
预处理条件命令。根据宏定义选择要编译的代码块。
3,写出bool、 float
、指针变量与 “零值 ”比较的if
语句
// float if ((f >= -0.000001) && (f <= 0.000001))){} // ptr if(p == nullptr){}
4,结构体可以直接赋值吗。
同类型之间可以。结构体内有裸指针需要注意相当于多个指针指向同块内存。
5,sizeof
和strlen
的区别
sizeof 是关键字、运算符,strlen 是库函数。
sizeof 返回的是内存大小。结果是编译时计算。参数可以是类型。
strlen 返回的是字符串长度且不包括null结束符。结果是运行时计算。参数只能是 char* 且必须以 '/0' 结尾。
6,static 关键字的作用
1,static 用来修饰【静态的】全局、局部 的 变量、函数。
2,被 static 修饰的变量或函数,内存空间存储于静态(全局)存储区,生命周期伴随整个程序生命周期。
3,此外还用来定义类静态类成员变量、函数。静态成员是属于整个类的而不是某个对象,静态成员变量只存储一份供所有对象共用。所以在所有对象中都可以共享它。使用静态成员变量实现多个对象之间的数据共享 不会破坏隐藏的原则,保证了安全性还可以节省内存。
4,静态局部变量在程序执行到该对象的声明处时被首次初始化,即以后的函数调用不再进行初始化;
5,静态局部变量一般在声明处初始化,如果没有显式初始化,会被程序自动初始化为 0;
6,全局静态变量是显式用 static 修饰的全局变量,作用域是声明此变量所在的文件,其他的文件即使用 extern 声明也不能使用。
7,C 语言的malloc
和 C++ 中的new
有什么区别
malloc 与 Free 是函数。new 与 delete 是C++关键字。
malloc 与 Free 不会调用构造、析构函数,仅仅是分配释放内存。new 与 delete 会调用构造、析构函数并分配或释放内存。
malloc 返回的是 void* 类型指针。new 返回的是带有类型的指针。
new 和 delete 在 C++ 中可以重载。
8,++i 和 i++ 的区别
++i 是先自增再赋值,先在局部变量自增再压栈。
i++ 是先赋值再自增,先压栈再在局部变量表中赋值。
++i 可以作为左值,i++则不行。
9,volatile 有什么作用
volatile 是指令关键字,确保本条指令不会因编译器的优化而省略,且要求每次直接读值。也就是不在CPU寄存器当中读取,每次都要重新从内存当中读取。
10, 一个参数可以既是const
又是volatile
吗
可以。
11,全局变量和局部变量的区别:
1,作用域不同、生命周期不同。
2,内存存储区域不同,全局变量存储于全局数据区,局部变量存储于栈区。
12,++i 和 i++区别
++i 是先自增后压栈。
i++ 先压入临时变量表,再在临时变量表中进行自增操作。
++i 可以作为左值,i++ 不行。
13,volatile
有什么作用
修饰某个变量,当读取该变量时,需要再次从内存中读取,而不是CPU寄存器当中。
可以和 const 结合使用。
14,全局变量和局部变量有什么区别?
1,生命周期不同、作用域不同。
2,内存存储空间不同,局部变量位于栈区,全局变量位于全局(静态)存储区。
15,简述 C、C++ 程序编译的内存分配情况
1,栈区:存放局部变量、函数参数传递的临时变量。
2,堆区:由程序执行动态分配,需要手动管理、容量大的内存区域。
3,常量池:存放常量的区域。
4,全局\静态区:存放全局变量及静态变量。
5,代码块
16,简述strcpy、sprintf
与memcpy
的区别
strcpy: 拷贝字符串从源地址到目标地址
memcpy: 拷贝内存块
sprintf: 本意是字符串格式化,将源字符串格式化拷贝到目标地址。
17,指针和引用的区别
相同点:都是基于地址的概念,指针是存储某块内存的地址,引用是某块内存的别名。
不同点:1,指针是实体,是变量。引用只是一个别名。
2,引用定义必须初始化且只能初始化一次,不能为空,且不可被改变。
3,sizeof 引用是获取的它所指向对象的大小,指针是指针变量本身的大小。
4,指针可以多级,引用只能一级。
18,typedef
和define
有什么区别?
typedef 是为变量定义别名,#defind是定义宏常量。
typedef 是运行时,#defind是编译时预处理指令。
typedef 有作用域,#defind 没有。
19,指针常量与常量指针区别?(中华语言博大精深)
int* const p;
指针常量:固定指向一块内存的指针,因为是常量所以值无法修改。
int const* p; const int* p;
常量指针:指向一个常量的指针。
20, 简述队列和栈的异同
共同点:都是线性表,都是在端点插入删除。
异同点:栈是先进后出,只能在一端修改(栈顶)。队列是队头插入、队尾删除,先进先出。
21,在C++中结构体与类的不同:
结构体对成员默认是public ,类默认是private。
22,句柄和指针的区别和联系是什么?
完全没有联系。
句柄是 Windows 系统标记资源的一种方式,类型是32位的unit。
指针是指向一块内存的变量。
23,extern“C”的作用:
extern "C"的主要作用就是为了能够正确实现C++代码调用其他C语言代码。加上extern "C"后,会指示编译器这部分代码按C语言的进行编译,而不是C++的。由于C++支持函数重载,因此编译器编译函数的过程中会将函数的参数类型也加到编译后的代码中,而不仅仅是函数名;而C语言并不支持函数重载,因此编译C语言代码的函数时不会带上函数的参数类型,一般只包括函数名。
24,C++ 类内可以定义引用数据成员吗?
可以,但是要在对象创建之时就初始化,也就意味着不能用空默认构造函数进行初始化。并且,构造函数参数必须也是同引用类型且必须在初始化表中初始化。
25,C++ 中类成员的访问权限及继承方式异同:
public 公有成员 :基类、派生类、友元、外部都可以访问
protected 保护成员: 基类、派生类、友元可以访问
private 私有成员 :基类、友元可以访问
继承方式 | 基类 public 成员 | 基类 protected 成员 | 基类 private 成员 |
public | public | protected | private |
protected | protected | protected | private |
privat | privat | private | private |
26,什么是右值引用,跟左值又有什么区别?
1、消除两个对象交互式时,不必要的拷贝,节省资源,提高效率;
2、简洁定义泛型函数;
左值:能取地址,或者具名对象,表达式结束后依然存在的持久对象;
右值:不能取地址,匿名对象,表达式结束后就不再存在的临时对象;
左值能寻址,右值不能;
左值能赋值,右值不能;
27, 用 C++ 设计一个不能被继承的类:
使用final关键字。
28,访问基类的私有虚函数
把问这个问题的人揍一顿。这种行为是卡编译器BUG。
29, 对虚函数和多态的理解
https://www.airchip.org.cn/index.php/2022/02/11/cpp-example-interface/
30,重写和重载的区别:
重载:返回值类型相同 函数名相同 参数不同
重写:子类覆写父类函数,返回值类型相同 函数名相同 参数相同,实现不同。
31,vector
中的reserve
和resize
的区别
reserve:重新分配堆内存空间
resize:修改长度,但不回收空间。
32, vector中的
size和
capacity的区别
size() (大小)指容器当前拥有元素的个数;
capacity() (容量)指容器在必须分配存储空间之前可以存储元素的总数(已用内存单元,单元大小由类型而定);
33,vector中erase方法与algorithm中的remove方法区别
erase删除一个元素后,相对应的元素被删除,并且容器中的元素也随之减少了一个,迭代器不能访问。
调用algorithm中的remove删除后相对应的元素被删除,但是容器中的元素个数没有变少,并且删除后容器后面的元素往前移动一个位置,并且最后的元素的值,是用之前最后一个元素的值填充。并且remove返回的迭代器位置是最后一个元素的位置。
34,正确释放vector
的内存
https://www.airchip.org.cn/index.php/2021/12/12/examplecvectordncqzhs/
35,什么情况下用vector,什么情况下用list,什么情况下用 deque
vector: 对象在内存中连续存储,随机访问性能高。(老头子说需要容器找它就对了)
list:对象在内存中分散存储,适合频繁写入修改,头插和尾插性能最高
deque: 合并了以上两者,连续空间存储的list,随机访问、双端修改性能好。但是资源消耗大,适合频繁增删改查的场景。
36,为何map和set的插入删除效率比其他序列容器高
MAP的节点是一对数据. SET的节点是一个数据.不需要内存的移动和拷贝。
37,为何map
和set
每次Insert
之后,以前保存的iterator
不会失效
因为每次插入删除会动态开辟释放内存空间,只有当前变化的节点iterator失效,之前保存的iterator由于内存空间未发生变化所以并不会失效。
38.map能不能边遍历边删除?
不可以,因为map删除了一个元素之后该元素对应节点的迭代器失效,且erase并不返回下一个元素的迭代器。
39,为何map
和set
每次Insert
之后,以前保存的iterator
不会失效?
在map和set当中, 迭代器相当于指向节点的指针。
40,为何map
和set
不能像vector
一样有个reserve
函数来预分配数据
原因在于在map和set内部存储的已经不是元素本身了,而是包含元素的节点。
41,hash_map
与map
的区别?什么时候用hash_map
,什么时候用map
1、STL的map底层是用红黑树实现的,查找时间复杂度是log(n);
2、STL的hash_map底层是用hash表存储的,查询时间复杂度是O(1);
hash_map 查找速度会比map快,而且查找速度基本和数据量大小无关,属于常数级别;而map的查找速度是log(n)级别。并不一定常数就比log(n) 小,hash还有hash函数的耗时。
42,static函数与普通函数有什么区别?
static 修饰的函数只能在当前代码文件中访问,并且会被分配到内存的静态区,整个生命周期只有一份。
43,在C语言中,为什么 static变量只初始化一次?
因为Static会被分配到内存的静态区,且在程序生命周期当中只有一份。
44,为什么基类的析构函数必须是虚函数?
1.析构函数不一定必须是虚函数,是否为虚函数取决于该类的使用,一般该类为基类产生继承和多态时,才会是虚函数,单独使用可以不是虚函数。之所以在继承和多态时设计为虚函数是因为当new派生类并且用基类指针指向这个派生类,在销毁基类指针时只会调用基类的析构函数,不会调用派生类的析构函数,因为基类无法操作派生类中非继承的成员,这样就造成派生类只new无法delete造成内存泄露。 2.默认不是虚析构函数是因为如果析构函数为虚函数就需要编译器在类中增加虚函数表来实现虚函数机制,这样所需内存空间就更大了,因此没有必要默认为虚析构函数。