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

C语言三维char数组内存分配错误排查与修复求助

内存分配错误与指针问题排查

问题现象

从文件读取二维数值数组并复制到C语言二维字符串数组时,出现以下错误:

  • 使用gdb调试时,执行free( tmval )触发munmap_chunk(): invalid pointer错误
  • 使用valgrind检测时,读写二维字符串数组出现多处Invalid write size of 8错误

问题代码段

//allocate memory for transition matrix
tm = (char ***) malloc( numstates*NUM_CLASSES-1*4*sizeof( char ) );

//initialize variables needed for loop
int i = 0;
char *tmval = (char *) calloc( 4, sizeof( char ) );

// read and process all the remaining lines from the file
while( fgets(buf, MAXBUF, fp) != NULL ) {
  //add comment detection
  if( buf[0] !='#' ){
    
    //allocate transition states for each row using calloc
    tm[i] = (char **) calloc( NUM_CLASSES-1, (4*sizeof( char )) );
  
    //strok first with space to skip row number
    ptr = strtok( buf, " " );
    
    for( int j = 0;j<NUM_CLASSES-1;j++ ){
      //allocate space for string in array
      tm[i][j] = (char *) calloc( 4, sizeof( char ) );
      tm[i][j] = "-1d";
    }

    //loop through line to get class numbers and corresponding states
    ptr = strtok( NULL, " " );
    while( ptr!=NULL ){
      int cls = strtol( ptr, end, 10 );
      tmval = *end+1;
      tm[i][cls] = tmval;
      ptr = strtok( NULL, " " );
    }
    
    //iterate i
    i++;
  }
}

//free up tmval and file
fclose( fp );
free( tmval );
free( end );

疑似问题代码

tm[i] = (char **) calloc( NUM_CLASSES-1, (3*sizeof( char )) );

输入文件格式

0  0/0d  1/0d  2/1s  3/3s  4/2s  5/2s  6/5s  7/4s  8/4s  10/9d
1  0/9d  1/9d  2/1s  3/1s  4/1s  5/1s  10/9d

注:第一个数字是行号,斜杠前为列号,斜杠后为对应值。

问题分析与修复方案

1. 内存分配大小不匹配(Valgrind错误根源)

  • 最外层指针数组tm的分配错误:
    tm是char***类型,每个元素是char**指针,正确逻辑应为numstates个char**指针分配内存,而非错误计算的numstates*NUM_CLASSES-1*4*sizeof(char)。
    修复:

    // 用calloc初始化所有指针为NULL更安全
    tm = calloc(numstates, sizeof(char**));
    
  • 每行指针数组tm[i]的分配错误:
    tm[i]是char**类型,每个元素是char*指针,需分配NUM_CLASSES-1个char*的大小,而非4*sizeof(char)(64位系统中char*占8字节,分配过小会导致越界写入)。
    修复:

    tm[i] = calloc(NUM_CLASSES-1, sizeof(char*));
    

2. 指针覆盖导致内存泄漏与无效指针

  • tm[i][j]的赋值错误:
    先通过calloc分配内存,随后直接赋值tm[i][j] = "-1d",将指针指向字符串常量,导致堆内存泄漏;后续tm[i][cls] = tmval同样直接覆盖指针,既泄漏内存,又让数组指向栈上的buf内存(tmval = *end+1指向buf内容),循环结束后buf被覆盖会产生野指针。
    修复:使用strcpy将字符串复制到已分配的内存中:
    // 初始化"-1d"时
    tm[i][j] = calloc(strlen("-1d") + 1, sizeof(char));
    strcpy(tm[i][j], "-1d");
    
    // 处理tmval时
    size_t val_len = strlen(tmval);
    tm[i][cls] = realloc(tm[i][cls], val_len + 1);
    strcpy(tm[i][cls], tmval);
    

3. free(tmval)错误的原因

tmval最初是calloc分配的堆内存,但tmval = *end+1将其指向了栈上的buf内存(strtok处理的是栈数组buf)。此时free(tmval)尝试释放栈内存,而非堆内存,触发invalid pointer错误。
修复:

  • 若不需要提前分配tmval,直接用栈变量临时存储字符串;
  • 若保留tmval,则不要修改其指向,而是将*end+1的内容复制到tmval中,再复制到tm[i][cls]。

4. free(end)的潜在问题

若end是栈上的指针(如char* end;),则不能调用free——free仅能释放malloc/calloc/realloc分配的堆内存。需检查end的定义,若未在堆上分配则删除free(end)。


内容的提问来源于stack exchange,提问作者Ray Babich

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 14:51:03