You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.28 04:45:02