C/C++面试必知:50道高频题深度解析
2025.09.19 14:37浏览量:0简介:本文汇总C/C++领域最常见的50道面试题,涵盖语言基础、内存管理、指针与引用、多线程等核心知识点,为开发者提供系统性复习框架与解题思路。
C/C++ 最常见50道面试题深度解析
一、语言基础与语法(10题)
C与C++的核心区别
C是过程式语言,依赖函数和结构体;C++是面向对象语言,支持类、继承、多态。C++在C基础上增加了模板、异常处理、STL等特性。例如,C中用malloc/free
管理内存,C++则推荐new/delete
或智能指针。static
关键字的作用- 局部变量:延长生命周期至程序结束,仅初始化一次。
- 全局变量:限制作用域为当前文件(内部链接)。
- 成员变量:所有对象共享同一副本。
- 成员函数:只能访问静态成员,无
this
指针。
const
与define
的区别const
是编译期常量,有类型检查和作用域;#define
是预处理宏,直接文本替换,可能导致边界问题(如#define MAX 100
在调试时无法查看值)。指针与引用的区别
指针可重新赋值,可为NULL
;引用是别名,必须初始化且不可更改绑定。例如:int a = 10;
int* p = &a; // 指针
int& r = a; // 引用
p = nullptr; // 合法
// r = nullptr; // 编译错误
sizeof
与strlen
的区别sizeof
是运算符,返回对象或类型的字节大小(如char arr[10]; sizeof(arr) = 10
);strlen
是函数,返回字符串长度(不包括\0
)。
二、内存管理与动态分配(8题)
内存泄漏的常见场景
- 忘记
delete
动态分配的对象。 - 异常导致
delete
未执行。 - 循环引用(智能指针需用
weak_ptr
解决)。
示例:void leak() {
int* p = new int[100];
throw std::runtime_error("error"); // 泄漏发生
delete[] p;
}
- 忘记
new
与malloc
的区别new
调用构造函数,delete
调用析构函数;malloc/free
仅分配/释放内存。new
失败时抛出std::bad_alloc
,malloc
返回NULL
。智能指针的类型与适用场景
unique_ptr
:独占所有权,不可复制。shared_ptr
:共享所有权,引用计数。weak_ptr
:解决循环引用,不增加计数。
示例:std::unique_ptr<int> up(new int(10));
std::shared_ptr<int> sp1(new int(20));
std::shared_ptr<int> sp2 = sp1; // 计数+1
浅拷贝与深拷贝的区别
浅拷贝仅复制指针值,导致多个对象共享同一内存;深拷贝分配新内存并复制内容。需自定义拷贝构造函数时(如含指针的类),必须实现深拷贝。placement new
的用途
在已分配的内存上构造对象,常用于内存池或嵌入式系统。示例:char buffer[sizeof(MyClass)];
MyClass* obj = new (buffer) MyClass(); // 在buffer上构造
三、面向对象与多态(12题)
虚函数与纯虚函数的区别
虚函数提供默认实现,子类可重写;纯虚函数(= 0
)无实现,强制子类重写。含纯虚函数的类为抽象类,不能实例化。构造函数能否为虚函数?
不能。构造函数执行时对象未完全构造,vptr
未初始化,无法确定虚函数表。多重继承的钻石问题与虚继承
多重继承可能导致基类子对象重复(如class D : public B1, public B2
,若B1
和B2
均继承A
)。虚继承(virtual
)可解决:class A {};
class B1 : virtual public A {};
class B2 : virtual public A {};
class D : public B1, public B2 {}; // 仅一个A子对象
override
与final
关键字的作用override
显式标记重写虚函数,编译期检查是否匹配基类声明;final
禁止子类进一步重写或继承。RTTI(运行时类型识别)的机制
通过dynamic_cast
和typeid
实现。dynamic_cast
用于安全向下转型,typeid
返回对象的类型信息(需包含<typeinfo>
)。
四、模板与泛型编程(8题)
函数模板与类模板的区别
函数模板实例化时推导类型参数;类模板需显式指定类型。示例:template <typename T>
T max(T a, T b) { return a > b ? a : b; } // 函数模板
template <typename T>
class Stack { /*...*/ }; // 类模板
模板特化与偏特化
全特化:为所有模板参数指定具体类型。偏特化:部分参数特化。示例:template <typename T>
class A {}; // 原模板
template <>
class A<int> {}; // 全特化
template <typename T>
class A<T*> {}; // 偏特化(指针类型)
可变参数模板的应用
用于实现泛型打印函数:void print() {}
template <typename T, typename... Args>
void print(T first, Args... args) {
std::cout << first << std::endl;
print(args...);
}
五、多线程与并发(6题)
std::mutex
与std::lock_guard
的配合lock_guard
在构造时加锁,析构时自动释放,避免忘记解锁。示例:std::mutex mtx;
{
std::lock_guard<std::mutex> lock(mtx);
// 临界区
} // 自动解锁
条件变量
std::condition_variable
的使用
需配合std::unique_lock
和谓词防止虚假唤醒:std::mutex mtx;
std::condition_variable cv;
bool ready = false;
// 等待线程
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, []{ return ready; });
// 通知线程
{
std::lock_guard<std::mutex> lock(mtx);
ready = true;
}
cv.notify_one();
六、STL与算法(6题)
vector
与list
的适用场景vector
随机访问快(O(1)
),插入/删除尾部快(O(1)
),中间插入慢(O(n)
);list
双向链表,插入/删除快(O(1)
),随机访问慢(O(n)
)。std::sort
与std::stable_sort
的区别std::sort
通常用快速排序或内省排序,不稳定;stable_sort
保证相等元素顺序,通常用归并排序。
七、高级特性(10题)
Lambda表达式的捕获方式
- 值捕获:
[x]
(副本)。 - 引用捕获:
[&x]
(可能悬空)。 - 隐式捕获:
[=]
(值)、[&]
(引用)。
示例:int x = 10;
auto f = [=]() { return x + 1; }; // 值捕获
- 值捕获:
noexcept
关键字的作用
标记函数是否可能抛出异常,影响移动语义和std::vector
的重新分配行为。constexpr
与编译期计算constexpr
函数在编译期求值,需满足简单条件(如无循环或递归)。示例:constexpr int factorial(int n) {
return n <= 1 ? 1 : n * factorial(n - 1);
}
八、系统级与底层知识(6题)
内存对齐的规则
结构体成员按最大对齐数排列,总大小为对齐数的整数倍。示例:struct A {
char c; // 1字节
int i; // 4字节(对齐到4)
double d; // 8字节(对齐到8)
}; // sizeof(A) = 16(1 + 3填充 + 4 + 8)
volatile
关键字的用途
禁止编译器优化,确保每次访问都从内存读取(常用于硬件寄存器或多线程共享变量)。
九、综合应用题(4题)
实现一个线程安全的单例模式
使用局部静态变量(C++11后线程安全)或双重检查锁定:class Singleton {
public:
static Singleton& getInstance() {
static Singleton instance;
return instance;
}
Singleton(const Singleton&) = delete;
private:
Singleton() {}
};
设计一个内存池
关键点:预分配大块内存,分割为固定大小块,用链表管理空闲块。需处理对齐和碎片问题。解析字符串中的整数(如
"123"
→123
)
需处理符号、溢出和非法字符:int parseInt(const char* str) {
int sign = 1, result = 0;
if (*str == '-') { sign = -1; str++; }
while (*str >= '0' && *str <= '9') {
int digit = *str - '0';
if (result > (INT_MAX - digit) / 10) throw std::overflow_error("overflow");
result = result * 10 + digit;
str++;
}
return sign * result;
}
备考建议
- 分模块复习:按语言基础、内存管理、面向对象等分类,每日攻克1-2个模块。
- 动手实践:对每个知识点编写代码验证,如实现智能指针或线程池。
- 模拟面试:与同伴互相提问,记录回答时间并优化表达。
- 查阅文档:熟悉
cppreference.com
等权威资料,避免依赖非标准实现。
通过系统性复习这50道高频题,开发者可全面掌握C/C++的核心知识点,在面试中展现扎实的技术功底。
发表评论
登录后可评论,请前往 登录 或 注册