C语言读取二维矩阵触发SIGSEGV,Valgrind报8字节未初始化值与无效读写错误
二维矩阵回读触发段错误问题
原始问题描述
我需要从之前自行生成的文件中读取二维矩阵,存储矩阵时采用的文件格式如下:
rowNum colNum -- 本场景下取值为2 [row1,col1] [row1,col2] [row2,col1] [row2,col2] [row3,col1] [row3,col2]
为实现文件回读,编写了如下函数:
// 读取数组,入参为文件路径、数组长度输出指针 int** readArray(char* file, int* arrayLengthNum) { FILE *fp = fopen(file, "r"); int bufferLength = 150; char buffer[bufferLength]; fgets(buffer, bufferLength, fp); int rows = atoi(buffer); fgets(buffer, bufferLength, fp); int cols = atoi(buffer); int** arr = malloc(rows*sizeof(int)); for(ssize_t i=0; i<rows ;i++) { arr[i]=malloc(cols*sizeof(int)); } for(ssize_t j=0; j<(rows*cols); j++) { fgets(buffer, bufferLength, fp); printf("The buffer: %s", buffer); arr[j/cols][j%2]=(int)atoi(buffer); } // 待优化为按引用传值逻辑 *arrayLengthNum=rows; fclose(fp); return arr; }
代码运行时始终触发SIGSEGV,Valgrind输出的报错信息如下:
==2378== Invalid write of size 8 ==2378== at 0x110445: readArray (arraySaving.h:38) ==2378== by 0x116A7D: main (main.c:108) ==2378== Address 0x4ba0028 is 117,064 bytes inside a block of size 117,068 alloc'd ==2378== at 0x483E77F: malloc (vg_replace_malloc.c:307) ==2378== by 0x110411: readArray (arraySaving.h:36) ==2378== by 0x116A7D: main (main.c:108) ==2378== ==2378== Use of uninitialised value of size 8 ==2378== at 0x1104BF: readArray (arraySaving.h:43) ==2378== by 0x116A7D: main (main.c:108) ==2378== ==2378== Invalid read of size 8 ==2378== at 0x110495: readArray (arraySaving.h:43) ==2378== by 0x116A7D: main (main.c:108) ==2378== Address 0x4ba0030 is 4 bytes after a block of size 117,068 alloc'd ==2378== at 0x483E77F: malloc (vg_replace_malloc.c:307) ==2378== by 0x110411: readArray (arraySaving.h:36) ==2378== by 0x116A7D: main (main.c:108) ==2378== ==2378== Invalid write of size 4 ==2378== at 0x1104BF: readArray (arraySaving.h:43) ==2378== by 0x116A7D: main (main.c:108) ==2378== Address 0x2f9800002eae is not stack'd, malloc'd or (recently) free'd ==2378== ==2378== Process terminating with default action of signal 11 (SIGSEGV): dumping core ==2378== Access not within mapped region at address 0x2F9800002EAE ==2378== at 0x1104BF: readArray (arraySaving.h:43) ==2378== by 0x116A7D: main (main.c:108) ==2378== If you believe this happened as a result of a stack ==2378== overflow in your program's main thread (unlikely but ==2378== possible), you can try to increase the size of the ==2378== main thread stack using the --main-stacksize= flag. ==2378== The main thread stack size used in this run was 8388608. ==2378== ==2378== HEAP SUMMARY: ==2378== in use at exit: 351,676 bytes in 29,269 blocks ==2378== total heap usage: 29,271 allocs, 2 frees, 356,796 bytes allocated ==2378== ==2378== LEAK SUMMARY: ==2378== definitely lost: 117,072 bytes in 14,634 blocks ==2378== indirectly lost: 0 bytes in 0 blocks ==2378== possibly lost: 0 bytes in 0 blocks ==2378== still reachable: 234,604 bytes in 14,635 blocks ==2378== suppressed: 0 bytes in 0 blocks ==2378== Rerun with --leak-check=full to see details of leaked memory ==2378== ==2378== Use --track-origins=yes to see where uninitialised values come from ==2378== For lists of detected and suppressed errors, rerun with: -s ==2378== ERROR SUMMARY: 13190 errors from 4 contexts (suppressed: 0 from 0) Segmentation fault (core dumped)
通过GDB调试观察到,数组下标似乎处于合法边界范围内,调试输出如下:
Program received signal SIGSEGV, Segmentation fault. 0x000055555555c4bf in readArray (file=0x55555556357d "/home/user/matrix", arrayLengthNum=0x7fffffffde10) at /home/user/filepath/arraySaving.h:43 43 arr[j/cols][j%2]=(int)atoi(buffer); (gdb) print (int)atoi(buffer) $1 = 119613727 (gdb) print j/cols $2 = 14636 (gdb) print j $3 = 29272 (gdb) print j%2 $4 = 0 (gdb)
错误根因
- 二维数组外层内存分配类型错误:
arr是int**类型,每个元素为int*指针,64位系统下单个指针占8字节,但分配外层数组时使用了malloc(rows*sizeof(int)),按int(4字节)计算所需内存,导致整个外层数组的可用空间只有预期的一半。 - 上述错误会直接引发内存越界:循环给
arr[i]赋值行指针时,写入位置会超过malloc分配的内存块边界,后续访问arr[i]时读到的是越界的非法地址,最终触发段错误。该问题与Valgrind输出中Address 0x4ba0030 is 4 bytes after a block of size 117,068 alloc'd的报错完全对应。 - 逻辑隐患:列下标硬编码为
j%2,通用实现应使用j%cols,当前列数为2时不会触发错误,后续修改列数会直接引发逻辑异常。
修正后代码
int** readArray(char* file, int* arrayLengthNum) { FILE *fp = fopen(file, "r"); if (!fp) { *arrayLengthNum = 0; return NULL; } int bufferLength = 150; char buffer[bufferLength]; fgets(buffer, bufferLength, fp); int rows = atoi(buffer); fgets(buffer, bufferLength, fp); int cols = atoi(buffer); // 修正外层分配的大小:按指针类型计算sizeof int** arr = malloc(rows * sizeof(int*)); if (!arr) { fclose(fp); *arrayLengthNum = 0; return NULL; } for(ssize_t i=0; i<rows ;i++) { arr[i] = malloc(cols * sizeof(int)); if (!arr[i]) { // 分配失败时释放已申请的内存,避免泄漏 for (ssize_t k=0; k<i; k++) free(arr[k]); free(arr); fclose(fp); *arrayLengthNum = 0; return NULL; } } for(ssize_t j=0; j<(rows*cols); j++) { fgets(buffer, bufferLength, fp); printf("The buffer: %s", buffer); // 修正列下标硬编码问题 arr[j/cols][j%cols] = atoi(buffer); } *arrayLengthNum = rows; fclose(fp); return arr; }
内容的提问来源于stack exchange,提问作者HonoredTarget
相关产品推荐
相关产品推荐

