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
相关产品推荐
相关产品推荐

