15 道初学者 C++ 面试题 — 答案短到能说出口
初级 C++ 面试高频题的简短诚实答案。边读边跑示例。
语言基础
1. 指针和引用的区别?
引用是别名 — 创建时必须绑定一个对象,终生不能改绑、不能为空。指针存地址:可以为空、可以重指向、可以做指针运算。经验法则:"必须有个对象"用引用;"可能没有对象"或需要挪动用指针。
2. 传值 vs 传引用 — 为什么重要?
传值拷贝参数,函数里的改动影响不到调用方。传引用把真身交给函数。大结构体应传 const 引用避免拷贝开销(下面的演示用指针 — 浏览器引擎暂不支持引用参数,思想相同:给地址而不是副本):
#include <iostream>
using namespace std;
void tryToChange(int x) { x = 99; } // 副本 — 调用方不受影响
void actuallyChange(int* x) { *x = 99; } // 真身的地址
int main() {
int a = 1;
tryToChange(a);
cout << "after tryToChange: " << a << endl;
actuallyChange(&a);
cout << "after actuallyChange: " << a << endl;
return 0;
}
3. const 是什么意思,面试为什么爱考?
const 是一个承诺:"这里不会被改。"const int* 指向"不能透过它改"的数据;int* const 是"不能再指向别处"的指针。参数和成员函数标 const 既写明意图,又让编译器替你抓错。
4. 声明和定义的区别?
声明说"有这么个东西"(int add(int, int););定义给出实际的函数体或存储(int add(int a, int b) { return a + b; })。声明可以很多次,定义只有一次。头文件因此存在。
5. #include 到底在干什么?
字面意义的文本粘贴:预处理阶段把头文件内容原样替换到那一行。这也是为什么同一头文件包含两次又不加 include guard 会报"重定义"。
内存 — 在这里分出"读过书"和"调过试"
6. 栈 vs 堆?
栈装局部变量;快、自动清理、容量小。堆装生命周期由你掌控的对象(new/delete),分配较慢,泄漏也住在这。现代 C++ 的答案:优先栈/自动存储;确需堆时用智能指针持有。
7. 一句话说清内存泄漏?
分配了堆内存却永远不会被释放 — 因为你失去了接触到它的最后手段。预防靠 RAII:把资源的生命周期绑到对象的作用域(std::unique_ptr、std::vector 干的就是这个)。
8. new 比 malloc 多给了什么?
一个类型正确的指针 — 而且它会运行对象的构造函数。malloc 只给回未初始化的原始字节(void*),对构造函数一无所知。现代代码里两者都很少直接调。
控制流与函数
9. ++i 与 i++ 的区别?
都加一。++i(前置)先加再交回新值;i++(后置)交回旧值再加。对类类型,前置可能更省(不用临时拷贝)— 一个受欢迎的细节题。
10. 什么是递归,它隐形的代价是什么?
函数调用自己,用基例刹车。隐形代价:每层调用吃栈空间 — 没有收紧基例的递归会爆栈(stack overflow!)。
#include <iostream>
using namespace std;
int fib(int n) {
if (n < 2) return n; // 基例
return fib(n - 1) + fib(n - 2); // 递归
}
int main() {
for (int i = 0; i <= 8; i++) {
cout << fib(i) << " ";
}
cout << endl;
return 0;
}
追问一定是:"这个斐波那契复杂度多少?" 答:O(2ⁿ) — 同样的值反复重算;用记忆化或迭代修是问题的下半场。
11. main 为什么特殊?
它是入口,标准只认两种签名:int main() 和 int main(int argc, char* argv[])(命令行参数)。不用你调 — 运行时会调。
类型与取值
12. 整数除法:C++ 里 7 / 2 是多少?
3 — 两边都是 int,结果就是 int(向零截断)。7.0 / 2 是 3.5,因为有一边是 double。经典 bug 源,所以是经典考题。
13. 什么是整数溢出,行为有定义吗?
有符号整数溢出是未定义行为 — 编译器可以假设它永不发生并据此优化。无符号整数按 2ⁿ 取模回绕,这是有定义的。
14. struct 与 class 的区别?
几乎没差:默认访问。struct 成员默认公有;class 默认私有。惯例:纯数据打包用 struct,有要守护的规则用 class。
15. main 里忘写 return 0; 会怎样?
没事 — main 是唯一一个隐式返回 0 的函数。在其他任何非 void 函数里,走着走着掉出函数尾是未定义行为。
怎么用这份清单
- 答案出声说,两句以内,然后主动给例子。面试官要的是清晰,不是背书。
- 上面每段代码都去练习场跑一遍再改一改 — 把
actuallyChange(int* x)改回传副本,运行前先预测输出。 - 两道内存题往下多挖一层;答得出"为什么"的初学者和只是"读过"的初学者,从这里分开。
相关阅读:C++ vector 与 array — 紧接着几乎必问的容器追问。