C/C++面试八股文精讲:从指针到网络编程的实战要点
1. 指针:C/C++的灵魂操作
指针是C/C++最核心也最让初学者头疼的概念。我当年第一次接触指针时,完全不明白这个"地址"到底有什么用。直到后来做图像处理项目时,需要直接操作内存中的像素数据,才真正体会到指针的强大。
指针变量本质上就是存储内存地址的容器。比如int *p = &a,这里的p就保存了变量a的内存首地址。几个关键点需要注意:
- 32位系统下指针固定占4字节,64位系统占8字节
- 未初始化的指针就像野马,使用会导致程序崩溃
- 指针运算时,
p+1实际移动的是sizeof(类型)的字节数
实际面试中常被问到的典型问题:
int a[5] = {1,2,3,4,5}; int *p = (int*)(&a + 1); printf("%d", *(p-1)); // 输出什么?这个例子考察的是指针运算和数组内存布局的理解。&a取到的是整个数组的地址,+1会跳过整个数组,所以p-1指向的是最后一个元素5。
2. 内存管理:从五大分区到常见陷阱
C/C++程序运行时,内存会被划分为五个关键区域:
- 栈区:自动管理,存放局部变量和函数调用信息
- 堆区:手动管理,通过
malloc/new动态申请 - 全局区:存放全局变量和静态变量
- 常量区:存放字符串常量等只读数据
- 代码区:存放程序执行的二进制指令
面试中最容易翻车的是内存泄漏问题。比如下面这个看似无害的函数:
char* getBuffer() { char buffer[100]; return buffer; // 严重错误! }这个函数返回了栈内存的指针,当函数返回后这块内存就会被回收。正确的做法应该是在堆上分配内存:
char* getBuffer() { char* buffer = (char*)malloc(100); return buffer; // 记得调用者要free }3. 字符串处理:安全第一
字符串操作是面试必考点,也是实际项目中最容易出安全问题的地方。strcpy这类不安全的函数现在基本都被strncpy_s等安全版本替代。几个常见陷阱:
strlen计算长度时不包含结尾的\0strcmp比较的是ASCII码值,不是长度strcat前必须确保目标缓冲区足够大
我曾经在项目中就遇到过因为strcpy导致的内存越界问题,最后用以下方式解决:
#define SAFE_COPY(dest, src, size) \ strncpy_s(dest, size, src, _TRUNCATE)4. TCP/IP网络编程核心要点
网络编程是C/C++面试的高频考点,特别是TCP的三次握手和四次挥手。用日常场景来理解:
三次握手就像打电话:
- A打给B:"喂,听得到吗?"
- B回复:"听得到,你听得到我吗?"
- A确认:"我也听得到"
四次挥手就像结束通话:
- A说:"我说完了"
- B确认:"好的"
- B也说:"我也说完了"
- A最后确认:"好的"
实际编程中要注意:
// 设置SO_REUSEADDR避免TIME_WAIT状态 int opt = 1; setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));5. 进程与线程:如何选择
选择进程还是线程,就像选择坐公交还是打车:
- 进程像公交车:独立路线(地址空间),安全但开销大
- 线程像拼车:共享路线(内存空间),高效但要协调
在多核处理器上,我通常这样选择:
- CPU密集型任务用多进程(避免GIL问题)
- I/O密集型任务用多线程(减少上下文切换开销)
一个实际项目中的经验:当需要处理上千个并发连接时,使用epoll+I/O多路复用配合线程池,比纯多线程或纯多进程方案性能提升明显。
6. 常见面试题精析
最后分享几个我面试别人时必问的题目:
问题1:sizeof和strlen有什么区别?
sizeof是运算符,编译时确定,计算内存大小strlen是函数,运行时计算,找\0位置
问题2:如何判断系统是大端还是小端?
int checkEndian() { int num = 1; return *(char*)&num == 1; // 返回1是小端 }问题3:写一个带长度检查的安全字符串拷贝函数
void safe_strcpy(char* dest, const char* src, size_t size) { if(size == 0) return; size_t i; for(i = 0; i < size-1 && src[i]; i++) { dest[i] = src[i]; } dest[i] = '\0'; }在准备C/C++面试时,建议把这些核心概念自己动手实现一遍,比单纯背诵要有效得多。我在招聘时更看重候选人是否能解释清楚代码背后的原理,而不仅仅是写出正确答案。
