C++/C方向面试题/概念知识点复习汇总(持续更新)

张开发
2026/4/6 1:23:54 15 分钟阅读

分享文章

C++/C方向面试题/概念知识点复习汇总(持续更新)
并非为面试准备而是集合所需知识点进行巩固加强印象1.讲讲同步和异步的区别同步是顺序执行调用者必须在等待一个任务完成后才可以进行下一个任务否则就阻塞住异步是并发执行调用者在发起任务之后立刻返回(通过回调函数Promise事件机制通知结果)期间可以去做其他的事情同步代码相对简单但是效率可能偏低(需要阻塞等待)适合需要强流程性的操作例如用户登录验证异步效率相对较高但代码较难(如回调地狱)适合实现一些I/O次数繁多密集的事务例如文件读写高并发接口网络请求拓展std::promise是一个线程之间传递结果的模板类和std::future搭配使用可以获得异步任务的返回值std::futureint compute_future() { std::promiseint prom; std::futureint fut prom.get_future(); std::thread([prom std::move(prom)]() mutable { std::this_thread::sleep_for(std::chrono::seconds(1)); prom.set_value(42); }).detach(); // 创建线程后detach(分离),之后不用join但也无法控制 return fut; // 返回 future } std::futureint result compute_future(); std::cout result.get(); // 输出 42 int compute_value() { std::this_thread::sleep_for(std::chrono::seconds(1)); return 42; } // 异步执行并自动获取 future std::futureint fut std::async(std::launch::async, compute_value); std::cout fut.get(); // 输出 422.函数指针和指针函数的理解函数指针是指针指向一个函数主要用于实现回调函数、策略模式等指针函数是函数返回一个指针通常用于动态内存分配(返回堆上创立的空间的起始指针)、工厂模式现代 C 中函数指针通常用std::function替代指针函数用智能指针返回更安全。拓展工厂模式是一种创建型设计模式用于封装对象的创建过程让客户端不直接 new 对象而是通过工厂方法来获取对象。例如类里的static一个对象创建函数在外通过类名直接调用3.如何保证线程安全首先线程安全是指多个线程并发访问共享数据时程序行为依然正确不会出现数据竞争、死锁等问题所以要保证线程安全主要需要解决数据之间的互相争抢访问期望控制共享数据的访问同时避免未定义行为有以下几点我们可以采用的方法互斥锁(Mutex)通过使用互斥锁mutex以及锁守卫lock_guard等确保同一时间只有一个线程可以访问临界区原子操作(Atomic)一些简单类型的数据可以用原子操作来避免锁开销并且保证原子性和内存顺序读写锁(Shared_mutex)使用读写锁保证同一时间只有一个线程去进行写操作(写独占)避免内存共享使用thread_local来避免共享内存每个线程拥有只属于自己的副本不用同步条件变量(Condition Variable)用于等待某个条件成立避免忙等待拓展死锁的原理以及避免死锁一般是由两个线程互相持有对方需要的锁并且都在等对方释放就会一直卡住谁都释放不了解决方法确保按顺序加锁确保所有线程都按照一致的顺序加锁这样就可以避免互相等的情况使用std::lock锁定多个互斥量std::lock一次性锁住多个互斥量且其中也有防死锁算法使用RAII避免忘记解锁将加锁操作放在构造函数解锁操作放在析构函数unique_lock和lock_guard的区别unique_lock的开销比lock_guard大但是unique_lock支持手动解锁内置lock()unlock()接口在wait()等地方必须使用unique_lock4.内存泄露是什么含义如何检测呢内存泄漏指的是在动态开辟内存时因为一些错误的操作在不再需要这块空间之后并没有及时或者无法释放该空间随着程序持续运行泄漏的内存会不断累积最终可能导致内存耗尽、程序崩溃或系统变慢静态分析编译器或工具检查代码模式发现可能的泄漏路径动态分析工具使用Valgrind等工具进行检查手动插桩检测重载new/delete并记录我觉得预防大于检测使用智能指针和RAII优先使用std::unique_ptr/std::shared_ptr管理动态内存自动释放。将泄露提前扼杀在摇篮5.多线程的适用场景多进程的适用场景首先多线程是共享进程地址空间切换很方便通信也方便但是隔离性不高一个线程崩全部就崩而且还需要处理同步(锁原子操作) 单核多进程拥有自己独立的地址空间隔离性强一个崩掉可以单独修复不会影响别的进程但是通信切换不方便更安全且可以跨多机多线程适用于需要高频共享数据、低延迟并行计算的场景比如图像处理、Web 服务器缓存共享。它的优点是通信快、切换轻量但缺点是需要处理锁竞争、死锁且一个线程崩溃会影响整个进程。多进程适用于需要高可靠性、安全隔离的场景比如浏览器标签页、守护监控进程。每个进程独立崩溃可单独恢复天然避免了锁问题但进程间通信如管道、共享内存开销较大创建成本也更高。在实际 C 开发中我会根据任务特点选择如果任务之间共享大量数据且频繁交互优先多线程 锁/无锁结构如果任务独立、需要强容错优先多进程 消息队列6.场景题单机TCP服务器和UDP服务器能不能占用同一个端口号可以。TCP 和 UDP 是独立的传输层协议操作系统维护独立的端口号空间。例如 DNS 服务器就同时监听 UDP 53 和 TCP 53。......操作系统的网络栈为每种协议维护独立的端口绑定表。即TCP 的 8080 号端口是一张表UDP 的 8080 号端口是另一张表。7.select和epoll的适用场景select在内核以及返回后的用户态都需要轮询一边所有fd来查找就绪id非常的耗时耗力epoll则是利用回调函数当就绪了回调函数就会把这个fd放入就绪链表所以只要检查链表为不为空然后复制到数组就行了省时省力select和epoll都是 I/O 多路复用机制但适用场景明显不同。select适合连接数较少通常 1024且所有连接都比较活跃的场景比如小型 demo、跨平台简单网络程序。它的缺点是每次调用都要线性扫描全部文件描述符连接数增加后效率线性下降。epoll适合高并发、大量连接数千到数十万且大部分连接处于空闲状态的场景比如 Web 服务器、即时通讯后端。它采用事件驱动方式只返回就绪的 fd时间复杂度 O(1)并且支持边缘触发性能远优于select。

更多文章