在 C/C++ 程序中,段错误(Segmentation Fault) 通常是由于程序访问了非法内存地址导致的。以下是常见原因及排查方法:
1. 空指针解引用
- 问题:对
NULL
或未初始化的指针进行读写。 - 示例:
int *p = NULL; *p = 10; // 段错误!
2. 野指针(Dangling Pointer)
- 问题:指针指向的内存已被释放(如
free
/delete
后继续访问)。 - 示例:
int *p = (int*)malloc(sizeof(int)); free(p); *p = 5; // 段错误!
3. 数组越界
- 问题:访问数组时超出其分配的空间。
- 示例:
int arr[5]; arr[10] = 0; // 越界访问!
4. 栈溢出(Stack Overflow)
- 问题:递归过深或局部变量占用过多栈空间。
- 示例:
void infinite_recursion() { infinite_recursion(); // 栈溢出! }
5. 只读内存写入
问题:尝试修改常量或代码段的只读内存。
示例:
char *str = "hello"; // "hello"在常量区 str[0] = 'H'; // 段错误! 正确做法: char str[] = "hello"; // 栈上可修改的副本 str[0] = 'H';
6. 内存对齐问题
- 问题:某些架构(如 ARM)要求内存对齐访问,未对齐的指针操作可能导致段错误。
- 示例:
uint32_t *ptr = (uint32_t*)(char_buffer + odd_offset); uint32_t value = *ptr; // CPU可能因未对齐报错
7. C++虚函数表破坏
- 问题:对象被提前释放后,通过基类指针调用虚函数。
- 示例:
class Base { public: virtual void foo() {} }; Base* b = new Base(); delete b; b->foo(); // vptr已失效,段错误!
▶️ 如何调试?
- GDB:
gcc -g program.c && gdb ./a.out
(gdb) run #运行到崩溃点
(gdb) backtrace #查看调用栈
(gdb) frame N #切换到具体栈帧
(gdb) print ptr #检查指针值
gcc -fsanitize=address program.c && ./a.out
# ASAN会直接报告非法内存位置
valgrind --tool=memcheck ./a.out
#检测野指针、越界等问题
ulimit -c unlimited #允许生成core文件
./a.out #崩溃后生成core
gdb a.out core #加载core文件分析
通过以上工具和方法,可以快速定位大部分段错误的根源。
内容由零声教学AI助手提供,问题来源于学员提问