无编译错误但运行崩溃的C程序问题排查求助
首先,你遇到的malloc.c断言失败错误,本质是堆内存被非法写入破坏了——你的程序越界读写了malloc分配的内存块,损坏了glibc内存分配器的内部元数据,导致后续执行printf(需要给stdout分配缓冲区时触发malloc)时触发断言崩溃。这个错误就是程序无提示崩溃的根本原因。
接下来逐个排查代码里的问题:
1. 内存分配的类型不匹配
在find_subseq函数中,你声明了int *arr,但分配内存时错误使用了sizeof(char):
int *arr = (int *)malloc(((la+1)*(lb+1)*sizeof(char)));
int通常是4字节(32/64位系统),而char是1字节,这意味着你只分配了实际需要内存的1/4。后续写入int类型的数据时,必然会越界,直接破坏堆结构。
修复:把sizeof(char)改成sizeof(int):
int *arr = malloc((la + 1) * (lb + 1) * sizeof(int));
(注:C语言中不需要强制转换malloc的返回值,避免隐藏潜在的类型问题)
2. 二维数组的索引计算完全错误
你试图用一维数组模拟二维数组,但索引公式完全错误:
- 正确的二维数组索引应该是
i*(lb+1) + j(因为每行有lb+1个元素) - 你的代码里用了
i*lb+j、i*(lb-1)+(j)等错误公式,直接导致访问到数组范围外的内存,破坏堆元数据。 - 初始化部分的循环逻辑也错了:第一个循环
i += (lb+1)根本无法正确初始化第一列,第二个循环初始化第一行的逻辑虽然方向对,但因为数组大小分配错误,同样会越界。
修复:修正所有索引计算:
// 初始化第一列(i从0到la) for(i = 0; i <= la; i++) { arr[i*(lb+1)] = 0; } // 初始化第一行(j从0到lb) for(j = 0; j <= lb; j++) { arr[j] = 0; } for(i = 1; i <= la; i++) { for(j = 1; j <= lb; j++) { if(a[i-1] == b[j-1]) // 这里还要注意字符串索引从0开始 arr[i*(lb+1)+j] = arr[(i-1)*(lb+1)+(j-1)] + 1; else arr[i*(lb+1)+j] = max(arr[(i-1)*(lb+1)+j], arr[i*(lb+1)+(j-1)]); } } // 返回正确的结果位置 return arr[la*(lb+1)+lb];
3. 字符串索引越界
C语言字符串的有效索引是从0到strlen(s)-1,但你的代码里用*(a+i)和*(b+j)(i从1到la,j从1到lb),这会访问到字符串末尾的\0之后的内存,属于非法访问,可能破坏其他内存区域。
修复:改成a[i-1]和b[j-1],对应字符串的第i-1和j-1个字符(和循环变量i/j的范围匹配)。
4. 输入缓冲区溢出风险
main函数里的scanf("%[^\n]%*c",a)没有限制输入长度,如果用户输入的字符串超过size-1(因为需要留一个字节给\0),会直接溢出a或b的内存块,破坏堆结构。
修复:限制输入长度,或者改用更安全的fgets:
// 用scanf限制长度,size是10000,所以最多读9999个字符 scanf("%9999[^\n]%*c", a); // 或者用fgets fgets(a, size, stdin); // 注意fgets会读取换行符,需要手动去掉 size_t len = strlen(a); if(len > 0 && a[len-1] == '\n') { a[len-1] = '\0'; }
额外建议:添加内存检查
每次malloc后都应该检查是否成功,避免内存分配失败导致的后续错误:
char* a = malloc(size*sizeof(char)); if(a == NULL) { perror("malloc failed for a"); exit(EXIT_FAILURE); }
把这些问题都修复后,程序的堆内存破坏问题就会解决,不会再出现断言失败和崩溃的情况。
内容的提问来源于stack exchange,提问作者PKBEST

