logo

C/C++面试必知:50道高频题深度解析

作者:梅琳marlin2025.09.19 14:37浏览量:0

简介:本文汇总C/C++领域最常见的50道面试题,涵盖语言基础、内存管理、指针与引用、多线程等核心知识点,为开发者提供系统性复习框架与解题思路。

C/C++ 最常见50道面试题深度解析

一、语言基础与语法(10题)

  1. C与C++的核心区别
    C是过程式语言,依赖函数和结构体;C++是面向对象语言,支持类、继承、多态。C++在C基础上增加了模板、异常处理、STL等特性。例如,C中用malloc/free管理内存,C++则推荐new/delete或智能指针。

  2. static关键字的作用

    • 局部变量:延长生命周期至程序结束,仅初始化一次。
    • 全局变量:限制作用域为当前文件(内部链接)。
    • 成员变量:所有对象共享同一副本。
    • 成员函数:只能访问静态成员,无this指针。
  3. constdefine的区别
    const是编译期常量,有类型检查和作用域;#define是预处理宏,直接文本替换,可能导致边界问题(如#define MAX 100在调试时无法查看值)。

  4. 指针与引用的区别
    指针可重新赋值,可为NULL;引用是别名,必须初始化且不可更改绑定。例如:

    1. int a = 10;
    2. int* p = &a; // 指针
    3. int& r = a; // 引用
    4. p = nullptr; // 合法
    5. // r = nullptr; // 编译错误
  5. sizeofstrlen的区别
    sizeof是运算符,返回对象或类型的字节大小(如char arr[10]; sizeof(arr) = 10);strlen是函数,返回字符串长度(不包括\0)。

二、内存管理与动态分配(8题)

  1. 内存泄漏的常见场景

    • 忘记delete动态分配的对象。
    • 异常导致delete未执行。
    • 循环引用(智能指针需用weak_ptr解决)。
      示例:
      1. void leak() {
      2. int* p = new int[100];
      3. throw std::runtime_error("error"); // 泄漏发生
      4. delete[] p;
      5. }
  2. newmalloc的区别
    new调用构造函数,delete调用析构函数;malloc/free仅分配/释放内存。new失败时抛出std::bad_allocmalloc返回NULL

  3. 智能指针的类型与适用场景

    • unique_ptr:独占所有权,不可复制。
    • shared_ptr:共享所有权,引用计数。
    • weak_ptr:解决循环引用,不增加计数。
      示例:
      1. std::unique_ptr<int> up(new int(10));
      2. std::shared_ptr<int> sp1(new int(20));
      3. std::shared_ptr<int> sp2 = sp1; // 计数+1
  4. 浅拷贝与深拷贝的区别
    浅拷贝仅复制指针值,导致多个对象共享同一内存;深拷贝分配新内存并复制内容。需自定义拷贝构造函数时(如含指针的类),必须实现深拷贝。

  5. placement new的用途
    在已分配的内存上构造对象,常用于内存池或嵌入式系统。示例:

    1. char buffer[sizeof(MyClass)];
    2. MyClass* obj = new (buffer) MyClass(); // 在buffer上构造

三、面向对象与多态(12题)

  1. 虚函数与纯虚函数的区别
    虚函数提供默认实现,子类可重写;纯虚函数(= 0)无实现,强制子类重写。含纯虚函数的类为抽象类,不能实例化。

  2. 构造函数能否为虚函数?
    不能。构造函数执行时对象未完全构造,vptr未初始化,无法确定虚函数表。

  3. 多重继承的钻石问题与虚继承
    多重继承可能导致基类子对象重复(如class D : public B1, public B2,若B1B2均继承A)。虚继承(virtual)可解决:

    1. class A {};
    2. class B1 : virtual public A {};
    3. class B2 : virtual public A {};
    4. class D : public B1, public B2 {}; // 仅一个A子对象
  4. overridefinal关键字的作用
    override显式标记重写虚函数,编译期检查是否匹配基类声明;final禁止子类进一步重写或继承。

  5. RTTI(运行时类型识别)的机制
    通过dynamic_casttypeid实现。dynamic_cast用于安全向下转型,typeid返回对象的类型信息(需包含<typeinfo>)。

四、模板与泛型编程(8题)

  1. 函数模板与类模板的区别
    函数模板实例化时推导类型参数;类模板需显式指定类型。示例:

    1. template <typename T>
    2. T max(T a, T b) { return a > b ? a : b; } // 函数模板
    3. template <typename T>
    4. class Stack { /*...*/ }; // 类模板
  2. 模板特化与偏特化
    全特化:为所有模板参数指定具体类型。偏特化:部分参数特化。示例:

    1. template <typename T>
    2. class A {}; // 原模板
    3. template <>
    4. class A<int> {}; // 全特化
    5. template <typename T>
    6. class A<T*> {}; // 偏特化(指针类型)
  3. 可变参数模板的应用
    用于实现泛型打印函数:

    1. void print() {}
    2. template <typename T, typename... Args>
    3. void print(T first, Args... args) {
    4. std::cout << first << std::endl;
    5. print(args...);
    6. }

五、多线程与并发(6题)

  1. std::mutexstd::lock_guard的配合
    lock_guard在构造时加锁,析构时自动释放,避免忘记解锁。示例:

    1. std::mutex mtx;
    2. {
    3. std::lock_guard<std::mutex> lock(mtx);
    4. // 临界区
    5. } // 自动解锁
  2. 条件变量std::condition_variable的使用
    需配合std::unique_lock和谓词防止虚假唤醒:

    1. std::mutex mtx;
    2. std::condition_variable cv;
    3. bool ready = false;
    4. // 等待线程
    5. std::unique_lock<std::mutex> lock(mtx);
    6. cv.wait(lock, []{ return ready; });
    7. // 通知线程
    8. {
    9. std::lock_guard<std::mutex> lock(mtx);
    10. ready = true;
    11. }
    12. cv.notify_one();

六、STL与算法(6题)

  1. vectorlist的适用场景
    vector随机访问快(O(1)),插入/删除尾部快(O(1)),中间插入慢(O(n));list双向链表,插入/删除快(O(1)),随机访问慢(O(n))。

  2. std::sortstd::stable_sort的区别
    std::sort通常用快速排序或内省排序,不稳定;stable_sort保证相等元素顺序,通常用归并排序。

七、高级特性(10题)

  1. Lambda表达式的捕获方式

    • 值捕获:[x](副本)。
    • 引用捕获:[&x](可能悬空)。
    • 隐式捕获:[=](值)、[&](引用)。
      示例:
      1. int x = 10;
      2. auto f = [=]() { return x + 1; }; // 值捕获
  2. noexcept关键字的作用
    标记函数是否可能抛出异常,影响移动语义和std::vector的重新分配行为。

  3. constexpr与编译期计算
    constexpr函数在编译期求值,需满足简单条件(如无循环或递归)。示例:

    1. constexpr int factorial(int n) {
    2. return n <= 1 ? 1 : n * factorial(n - 1);
    3. }

八、系统级与底层知识(6题)

  1. 内存对齐的规则
    结构体成员按最大对齐数排列,总大小为对齐数的整数倍。示例:

    1. struct A {
    2. char c; // 1字节
    3. int i; // 4字节(对齐到4)
    4. double d; // 8字节(对齐到8)
    5. }; // sizeof(A) = 16(1 + 3填充 + 4 + 8)
  2. volatile关键字的用途
    禁止编译器优化,确保每次访问都从内存读取(常用于硬件寄存器或多线程共享变量)。

九、综合应用题(4题)

  1. 实现一个线程安全的单例模式
    使用局部静态变量(C++11后线程安全)或双重检查锁定:

    1. class Singleton {
    2. public:
    3. static Singleton& getInstance() {
    4. static Singleton instance;
    5. return instance;
    6. }
    7. Singleton(const Singleton&) = delete;
    8. private:
    9. Singleton() {}
    10. };
  2. 设计一个内存池
    关键点:预分配大块内存,分割为固定大小块,用链表管理空闲块。需处理对齐和碎片问题。

  3. 解析字符串中的整数(如"123"123
    需处理符号、溢出和非法字符:

    1. int parseInt(const char* str) {
    2. int sign = 1, result = 0;
    3. if (*str == '-') { sign = -1; str++; }
    4. while (*str >= '0' && *str <= '9') {
    5. int digit = *str - '0';
    6. if (result > (INT_MAX - digit) / 10) throw std::overflow_error("overflow");
    7. result = result * 10 + digit;
    8. str++;
    9. }
    10. return sign * result;
    11. }

备考建议

  1. 分模块复习:按语言基础、内存管理、面向对象等分类,每日攻克1-2个模块。
  2. 动手实践:对每个知识点编写代码验证,如实现智能指针或线程池。
  3. 模拟面试:与同伴互相提问,记录回答时间并优化表达。
  4. 查阅文档:熟悉cppreference.com等权威资料,避免依赖非标准实现。

通过系统性复习这50道高频题,开发者可全面掌握C/C++的核心知识点,在面试中展现扎实的技术功底。

相关文章推荐

发表评论