什么是 "Core Dumped"?
"Core Dumped" 意味着你的程序崩溃了,并且操作系统将程序崩溃那一刻的内存状态(称为 "core dump" 或 "核心转储")保存到了一个文件中。

这就像飞机失事后的“黑匣子”,记录了飞机(程序)在坠毁(崩溃)前的所有关键数据(内存、寄存器状态等),这个文件通常命名为 core,或者 core.pid(pid 是进程ID)。
为什么叫 "Core"? 在早期计算机中,内存是由微小的磁环(magnetic cores)构成的,因此内存的核心部分就被称为 "core",保存内存状态的行为就叫做 "dumping the core"。
关键点:
- 它不是一个编译错误:你的代码可以成功编译和链接,这是一个运行时错误。
- 它是一个严重错误:程序已经无法继续执行,操作系统为了系统的稳定性,只能终止它。
- 它是一个线索,而不是最终答案:
core dumped本身只告诉你“程序挂了”,真正的凶手(错误代码)需要你去core文件里找。
为什么会发生 "Core Dumped"?
几乎所有的 core dumped 错误都是由内存访问违规引起的,程序试图访问一块它“无权”访问的内存区域。

最常见的“元凶”是以下三种:
解引用空指针
这是最经典、最常见的错误,你创建了一个指针,但它没有指向任何有效的内存地址(它的值是 NULL 或 0),然后你试图通过这个指针去访问或修改内存。
示例代码:
#include <stdio.h>
int main() {
int *ptr = NULL; // ptr 是一个空指针
*ptr = 10; // 尝试解引用空指针,向 NULL 地址写入数据 -> BANG! Core Dumped
printf("这行代码永远不会执行\n");
return 0;
}
为什么会崩溃?
操作系统规定,地址 0 是一个特殊的受保护地址,任何程序都无权访问它,当你试图向 *ptr (即地址 0) 写入数据时,CPU 的内存管理单元会检测到这个非法操作,立即终止程序并生成 core 文件。

解引用未初始化的指针
指针变量本身是一个变量,它也需要被初始化,即分配一个有效的内存地址,如果你没有初始化它,它就会包含一个“垃圾值”,这个垃圾值可能是一个随机的、无效的内存地址。
示例代码:
#include <stdio.h>
int main() {
int *ptr; // ptr 没有被初始化,它包含一个垃圾值
*ptr = 20; // 尝试向一个随机的、未知地址写入数据 -> BANG! Core Dumped
printf("这行代码也永远不会执行\n");
return 0;
}
为什么会崩溃?
ptr 的垃圾值可能指向操作系统内核空间、其他程序的内存,或者一个你没有写入权限的内存区域,无论哪种情况,访问它都会导致段错误。
数组越界访问
当你访问数组时,C 语言不会检查你的索引是否合法,如果你访问了超出数组边界的元素,你就会修改到数组以外的内存,这块内存可能属于其他变量,也可能属于程序的其他部分,甚至可能是受保护的系统内存。
示例代码:
#include <stdio.h>
int main() {
int arr[5] = {1, 2, 3, 4, 5};
int *ptr = &arr[0];
// arr 的有效索引是 0, 1, 2, 3, 4
// 访问 arr[5] 就越界了
printf("arr[5] 的值是: %d\n", arr[5]); // 读取越界,可能读到垃圾数据,也可能不崩溃
arr[5] = 10; // 写入越界,很可能破坏了其他数据,最终导致程序逻辑错误或崩溃 -> BANG! Core Dumped
// 更隐蔽的指针越界
ptr = &arr[0];
*(ptr + 5) = 20; // 等同于 arr[5] = 20,同样会导致越界写入
return 0;
}
为什么会崩溃? 你写入的这块“越界”内存,可能恰好是程序运行所必需的关键数据(比如函数的返回地址),破坏了它就会导致程序执行流混乱,最终崩溃。
如何调试 "Core Dumped"?(实战指南)
当看到 Segmentation fault (core dumped) 时,不要慌,按照以下步骤来,你一定能找到问题所在。
步骤 1:确保系统允许生成 Core 文件
系统出于安全考虑会限制 core 文件的生成,你需要检查并设置。
-
检查当前限制:
ulimit -a
找到
core file size这一项,如果它被设置为0,就意味着系统不允许生成core文件。 -
临时设置(仅对当前终端有效):
ulimit -c unlimited
这会允许生成任意大小的
core文件,调试完成后可以恢复为ulimit -c 0。 -
永久设置(需要管理员权限): 编辑
/etc/security/limits.conf文件,添加或修改以下行:* soft core unlimited * hard core unlimited然后重启或重新登录。
步骤 2:编译时开启调试信息
为了能将 core 文件中的内存地址映射到你源代码的具体行数,必须在编译时加上 -g 标志。
gcc -g your_program.c -o your_program
不加 -g 的话,调试器将无法显示源代码行号,排查起来会非常困难。
步骤 3:复现并定位崩溃
-
运行你的程序:
./your_program
程序崩溃后,在当前目录下会生成一个
core文件(或core.pid)。 -
使用 GDB 进行调试: GDB (GNU Debugger) 是 Linux/Unix 下最强大的调试工具。
gdb ./your_program core
或者,GDB 能自动找到
core文件:gdb ./your_program (gdb) core-file core
-
在 GDB 中执行命令: 一旦进入 GDB,你会看到
(gdb)提示符,输入以下命令:-
bt(或backtrace): 这是最关键的命令! 它会打印出程序崩溃时的函数调用栈,你会看到一条从main()函数开始的调用链,直到发生错误的那一行,这通常能直接告诉你错误发生在哪个文件的哪一行。(gdb) bt #0 0x0000000000400546 in main () at your_program.c:6 #1 0x00007ffff7a1c515 in __libc_start_main (main=0x4004d0, argc=1, argv=0x7fffffffe5d8, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffe5c8) at ../csu/libc-start.c:261 #2 0x0000000000400579 in _start ()这个例子清晰地表明,错误发生在
your_program.c文件的第6行。 -
list(或l): 显示bt定位到的那行代码及其周围的源代码。(gdb) list 1 #include <stdio.h> 2 3 int main() { 4 int *ptr = NULL; 5 6 *ptr = 10; 7 8 printf("这行代码永远不会执行\n"); 9 return 0; 10 }现在你已经找到了罪魁祸首:第 6 行的
*ptr = 10;。 -
info locals(或info frame): 在bt的某个帧上使用,可以查看该帧的局部变量值,在#0帧上使用,可以查看ptr的值,确认它确实是0x0(NULL)。 -
quit: 退出 GDB。
-
步骤 4:修复代码
根据 GDB 提供的线索,回到你的源代码,修复那个导致内存访问违规的错误。
- 如果是空指针:在使用指针前,检查它是否为
NULL。if (ptr != NULL) { *ptr = 10; } else { printf("错误:指针为空!\n"); } - 如果是未初始化指针:在使用前确保它已经指向了有效的内存(通过
malloc分配,或让它指向一个已存在的变量)。int value; int *ptr = &value; // 指向一个已存在的变量 // 或者 int *ptr = malloc(sizeof(int)); // 动态分配内存 if (ptr != NULL) { *ptr = 20; // ... 使用后 ... free(ptr); // 别忘了释放! } - 如果是数组越界:确保你的循环或索引在
[0, size-1]的范围内。int arr[5]; for (int i = 0; i < 5; i++) { // 注意是 i < 5, 不是 i <= 5 arr[i] = i; }
Cored Dumped 检查清单
当你遇到这个错误时,按顺序检查以下事项:
- 心态:保持冷静,这是一个可以解决的问题。
- 编译:确保用
-g标志重新编译了你的代码。 - 运行:再次运行程序,确保生成了
core文件。 - 调试:用
gdb ./your_program core启动调试器。 - 核心命令:在 GDB 中输入
bt查看调用栈,找到出错的代码行。 - 分析:根据
bt的提示,检查那一行是否存在空指针解引用、未初始化指针或数组越界。 - 修复:修复代码,然后重新编译、运行、测试。
通过这套流程,绝大多数的 Segmentation fault 问题都能被快速定位和解决,祝你编程顺利!
