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 函数里,走着走着掉出函数尾是未定义行为。

怎么用这份清单

相关阅读:C++ vector 与 array — 紧接着几乎必问的容器追问。