C/C++面试宝典
深度解析 C/C++ 核心技术栈,涵盖从 指针内存管理 到 高并发架构设计 的全方位面试指南。
专为追求卓越的开发者打造,助您轻松攻克 BAT、字节跳动、腾讯等大厂技术面试。
一、C/C++ 基础核心考点
在 C/C++ 面试中,基础知识的扎实程度往往决定了面试官对你的第一印象。C/C++面试宝典 认为,理解语言底层机制比单纯记忆语法更为重要。以下是近年来大厂面试中最常考察的基础知识点。
1. 指针与引用的本质区别
指针(Pointer)和引用(Reference)是 C++ 区别于 C 语言的重要特性,也是面试必问环节。指针是一个变量,存储的是内存地址;而引用是变量的别名,在内存中不单独存在,通常在编译期实现。
- 初始化要求: 指针可以指向空(NULL),但引用必须在定义时初始化,且不能更改指向。
- 内存占用: 指针本身占用内存(4字节或8字节),引用通常通过指针实现,但编译器优化后可能不占用额外空间。
- 多级指针: 支持多级指针(如 int),引用不支持多级引用。
int a = 10; int p = &a; // 指针:存储地址,可修改指向 int& r = a; // 引用:别名,不可更改绑定 // p = nullptr; // 合法 // r = nullptr; // 错误:引用不能为空
2. 静态绑定与动态绑定
C/C++面试宝典 提示:理解多态的关键在于动态绑定。静态绑定发生在编译期,基于指针或引用的类型;动态绑定发生在运行期,基于对象的实际类型,需要通过虚函数表(vtable)实现。
静态绑定 (Static Binding)
编译器在编译阶段确定调用哪个函数。通常用于非虚函数、重载函数。
动态绑定 (Dynamic Binding)
程序在运行阶段根据对象实际类型确定调用哪个函数。必须满足:基类指针/引用 + 虚函数。
二、进阶原理与内存管理
掌握内存管理是成为高级 C++ 工程师的必经之路。面试官通常会通过内存泄漏、野指针、栈溢出等问题考察候选人的底层功底。
1. 内存分区模型
C++ 程序在内存中主要分为五个区:
| 内存区 | 存放内容 | 生命周期 | 管理方式 |
|---|---|---|---|
| 栈区 (Stack) | 局部变量、函数参数、返回值 | 函数执行完毕自动释放 | 编译器自动管理 |
| 堆区 (Heap) | new/malloc 分配的动态内存 | 手动 delete/free,否则泄漏 | 程序员手动管理 |
| 全局/静态区 | 全局变量、static 变量、常量 | 程序运行全程 | 编译器自动管理 |
| 常量区 | 字符串常量、const 修饰的常量 | 程序运行全程 | 编译器自动管理 |
| 代码区 | 函数体的二进制代码 | 程序运行全程 | 操作系统管理 |
2. 智能指针深度解析
现代 C++(C++11 及以上)推荐使用智能指针替代裸指针,以避免内存泄漏。C/C++面试宝典 整理了三种主要智能指针的核心区别:
- unique_ptr: 独占式拥有,不可拷贝,可移动。适用于资源唯一拥有的场景,性能最优。
- shared_ptr: 共享式拥有,引用计数。当最后一个 shared_ptr 销毁时释放资源。注意循环引用问题,需配合 weak_ptr 使用。
- weak_ptr: 弱引用,不增加引用计数。用于打破循环引用,观察 shared_ptr 的状态。
#include <memory> #include <iostream> void smart_ptr_demo() { std::unique_ptr<int> uptr(new int(10)); // std::unique_ptr<int> uptr2 = uptr; // 错误:禁止拷贝 std::unique_ptr<int> uptr2 = std::move(uptr); // 正确:转移所有权 std::shared_ptr<int> sptr1(new int(20)); std::shared_ptr<int> sptr2 = sptr1; std::cout << sptr1.use_count() << std::endl; // 输出: 2 }
三、STL 源码剖析与容器选型
标准模板库(STL)是 C++ 程序员的利器。面试官常问 vector 和 list 的区别,或者 map 的底层实现。理解其底层数据结构是回答这些问题的关键。
1. 常用容器底层结构
std::vector
底层结构: 动态数组(连续内存)。
特点: 支持随机访问(O(1)),尾部插入/删除高效(均摊 O(1)),中间插入/删除低效(O(N))。
扩容机制: 当容量不足时,通常按 2 倍容量重新分配内存,拷贝原有数据,释放旧内存。
面试要点: 避免频繁扩容,可预先 reserve 空间;erase 迭代器失效问题。
std::list
底层结构: 双向链表。
特点: 不支持随机访问,插入/删除高效(O(1)),内存不连续,缓存命中率低。
面试要点: 适用于频繁插入删除且不需要随机访问的场景;迭代器失效仅影响被删除元素的迭代器。
std::map / std::set
底层结构: 红黑树(自平衡二叉搜索树)。
特点: 有序(默认升序),查找/插入/删除均为 O(log N)。
面试要点: map 是键值对,set 只有键;底层实现一致,仅接口不同;迭代器失效问题与 vector 类似。
四、设计模式与系统架构
除了语言本身,设计模式和系统架构能力也是区分初级与高级开发者的关键。C/C++面试宝典 整理了后端开发中最常用的几种设计模式及其应用场景。
1. 单例模式 (Singleton)
单例模式确保一个类只有一个实例,并提供一个全局访问点。在 C++ 中,实现线程安全的单例有多种方式:
- 饿汉式: 全局静态变量,线程安全,但可能浪费资源。
- 懒汉式(双重检查锁): 第一次使用时创建,需加锁保证线程安全,性能较好。
- Meyers Singleton(C++11): 利用局部静态变量的线程安全性,推荐方式。
class Singleton { public: static Singleton& getInstance() { static Singleton instance; // C++11 起保证线程安全 return instance; } Singleton(const Singleton&) = delete; Singleton& operator=(const Singleton&) = delete; private: Singleton() {} };
2. 观察者模式 (Observer)
观察者模式定义了对象间的一对多依赖,当一个对象状态改变时,所有依赖者都会收到通知并更新。广泛应用于事件处理系统、发布-订阅模型中。
五、系统架构与计算机网络
后端开发离不开对操作系统和网络协议的理解。以下是 C/C++ 开发者必须掌握的系统级知识。
1. TCP/UDP 区别与应用场景
TCP (传输控制协议)
面向连接、可靠传输、面向字节流。适用于文件传输、邮件、网页浏览等对数据完整性要求高的场景。
UDP (用户数据报协议)
无连接、不可靠、面向数据报。适用于视频直播、在线游戏、DNS 查询等对实时性要求高的场景。
2. IO 多路复用:select/poll/epoll
在高并发服务器开发中,IO 多路复用是核心机制。
- select: 限制文件描述符数量(通常 1024),线性扫描,效率低。
- poll: 无 FD 数量限制,但仍需线性扫描,效率随连接数增加而下降。
- epoll: Linux 特有,基于事件驱动,O(1) 复杂度获取就绪 FD,适用于高并发场景(如 Nginx、Redis)。
六、网友最关心的 10 个面试问题
根据 C/C++面试宝典 的后台数据统计,以下是求职者最常搜索和关注的问题,我们提供了深度解答。
每个包含虚函数的类都有一个虚函数表,表中存储了虚函数的地址。类的实例中隐藏了一个 vptr,指向该表。调用虚函数时,通过 vptr 找到 vtable,再根据偏移量调用具体函数。
new 是操作符,可重载,调用构造函数,返回具体类型指针;malloc 是库函数,无法重载,不调用构造函数,返回 void,需手动强制转换。
右值引用(&&)绑定到右值(临时对象)。移动语义通过 std::move 将资源所有权从一个对象转移到另一个对象,避免深拷贝,提高性能。
使用 weak_ptr 打破循环。weak_ptr 不增加引用计数,可观察 shared_ptr 的状态,在需要时通过 lock() 获取 shared_ptr。
资源获取即初始化(Resource Acquisition Is Initialization)。利用对象生命周期管理资源,构造函数获取资源,析构函数释放资源,确保异常安全。
进程是资源分配的最小单位,线程是 CPU 调度的最小单位。进程间通信复杂(IPC),线程间共享内存,通信简单但需同步。
死锁是多个线程互相等待对方释放资源。避免方法:破坏互斥条件、破坏占有并等待、破坏不可抢占、破坏循环等待(如按顺序加锁)。
11: auto, nullptr, 右值引用, 智能指针, 线程库;14: lambda 改进, 泛型 lambda;17: if/switch 初始化, 结构化绑定, filesystem;20: concepts, modules, coroutines。
当通过基类指针删除派生类对象时,如果基类析构函数不是虚函数,只会调用基类析构函数,导致派生类资源泄漏。因此,有虚函数的类通常应有虚析构函数。
减少动态内存分配,使用局部变量,避免虚函数调用开销,使用移动语义,优化数据结构,使用缓存友好性设计, profiling 定位瓶颈。
七、网友们还关心:周边知识与学习路径
除了核心的 C/C++ 技术栈,C/C++面试宝典 发现求职者还非常关注与后端开发紧密相关的周边知识。这些知识往往能在面试中成为加分项。
1. Linux 操作系统基础
C/C++ 开发者绝大多数工作在 Linux 环境下。熟悉常用命令(ls, grep, awk, sed, top, ps)、Shell 脚本编写、文件系统权限管理是基本要求。
2. 数据库知识 (MySQL/Redis)
后端开发离不开数据库。了解 MySQL 的索引结构(B+树)、事务隔离级别、锁机制,以及 Redis 的数据结构、持久化机制(RDB/AOF)、缓存穿透/击穿/雪崩解决方案,是面试中的高频考点。
3. 中间件与分布式系统
对于高级岗位,了解消息队列(Kafka/RabbitMQ)、分布式一致性协议(Raft/Paxos)、服务治理(Dubbo/Spring Cloud)等知识,有助于展示架构视野。
4. 算法与数据结构
LeetCode 刷题是面试准备的重中之重。重点掌握数组、链表、树、图、动态规划、回溯等经典算法。C++ STL 中的 sort、lower_bound 等函数需熟练使用。
5. 项目经验梳理
面试官非常关注项目细节。建议使用 STAR 法则(Situation, Task, Action, Result)梳理项目经验,突出自己在项目中解决的技术难点、性能优化手段和团队协作能力。
💡 学习建议
技术学习是一个持续的过程。C/C++面试宝典 建议您制定合理的学习计划,从基础语法入手,逐步深入底层原理,结合项目实践,不断复盘总结。祝您早日拿到心仪的 Offer!