如何在结构体数组中分配字符串数组?程序崩溃问题排查
结构体char**数组内存分配与访问崩溃问题
头文件定义
#ifndef SDL2_BATIMENTS_H #define SDL2_BATIMENTS_H typedef struct{ int x; int y; }vecteur; typedef struct{ int numtype; // 决定建筑的显示样式(北路/南路等) char** tabpath; // 图片路径数组 vecteur size; // 建筑尺寸(x,y) int habitant; }batiment; typedef struct { vecteur** tuile; batiment* tabbatiment; // 建筑数组 }Monde; Monde* InitBatiment(Monde* monde); vecteur toGrid(float x,float y); #endif //SDL2_BATIMENTS_H
首次内存分配代码(访问时崩溃)
尝试为batiment中的char** tabpath分配二维数组内存,无编译错误但访问时程序崩溃:
for(int i=0; i<14;i++) { monde->tabbatiment[i].tabpath = malloc(7 * sizeof (char*)); for (int y = 0; y < 7; y++) monde->tabbatiment[i].tabpath[i] = (char*)malloc(50 * sizeof(char)); }
修改后的代码(strcpy调用时仍崩溃)
改用calloc分配内存后,调用strcpy时程序依然崩溃:
for(int i=0; i<14;i++) { monde->tabbatiment[i].tabpath = calloc(10,sizeof(char*)); for(int y = 0; y < 10; y++) monde->tabbatiment[i].tabpath[i] = calloc(30 ,sizeof(char)); } FILE *f; char c; int numbatiment; f=fopen("batiment.txt","r"); int x,y,numbat,numtype; const char path[50]; for(int i =0;i<16;i++) { fscanf(f,"%d %d %d %d %s ",&numbat,&x,&y,&numtype,&path); printf("%s",path); strcpy(monde->tabbatiment[numbat].tabpath[numtype],path); monde->tabbatiment[numbat].size.x = x ; monde->tabbatiment[numbat].size.y=y ; monde->tabbatiment[numbat].numtype = numtype; printf("%d %d %d %d %s\n",numbat,monde->tabbatiment[numbat].size.x,monde->tabbatiment[numbat].size.y,monde->tabbatiment[numbat].numtype,monde->tabbatiment[numbat].tabpath[numtype]); } fclose(f);
问题根源
- 内层循环下标错误:两次分配内存时,内层循环都错误使用外层的
i作为tabpath的下标,而非内层的y。这会导致:- 每次内层循环都覆盖
tabpath[i]的地址,其他下标(0到i-1、i+1到9)的指针要么未初始化(malloc版本),要么为NULL(calloc版本) - 当
i >=10时,tabpath[i]会越界访问,破坏内存结构
- 每次内层循环都覆盖
- 数组越界访问:
- 仅分配了14个建筑的
tabpath,但读取文件时循环16次,若numbat取值超过13,会越界访问tabbatiment数组 numtype若超过9,会越界访问仅分配了10个指针的tabpath
- 仅分配了14个建筑的
- 变量未初始化:
const char path[50];未初始化,直接写入存在垃圾数据风险
修复方案
// 正确分配内存,添加错误检查 for(int i=0; i<14;i++) { monde->tabbatiment[i].tabpath = calloc(10, sizeof(char*)); if (monde->tabbatiment[i].tabpath == NULL) { perror("calloc tabpath failed"); // 释放已分配内存并返回错误 for(int k=0; k<i; k++) { for(int y=0; y<10; y++) { free(monde->tabbatiment[k].tabpath[y]); } free(monde->tabbatiment[k].tabpath); } return NULL; } for(int y = 0; y < 10; y++) { monde->tabbatiment[i].tabpath[y] = calloc(30, sizeof(char)); if (monde->tabbatiment[i].tabpath[y] == NULL) { perror("calloc path failed"); // 释放当前tabpath下已分配的指针 for(int k=0; k<y; k++) { free(monde->tabbatiment[i].tabpath[k]); } free(monde->tabbatiment[i].tabpath); // 释放之前分配的其他建筑内存 for(int k=0; k<i; k++) { for(int z=0; z<10; z++) { free(monde->tabbatiment[k].tabpath[z]); } free(monde->tabbatiment[k].tabpath); } return NULL; } } } // 打开文件并检查 FILE *f = fopen("batiment.txt", "r"); if (f == NULL) { perror("fopen failed"); // 释放已分配内存 for(int i=0; i<14; i++) { for(int y=0; y<10; y++) { free(monde->tabbatiment[i].tabpath[y]); } free(monde->tabbatiment[i].tabpath); } return NULL; } int x, y, numbat, numtype; char path[50] = {0}; // 初始化路径缓冲区 // 限制循环次数为建筑数组长度,避免越界 for(int i =0; i<14; i++) { // 检查读取是否成功 if (fscanf(f, "%d %d %d %d %s", &numbat, &x, &y, &numtype, path) != 5) { break; } // 检查下标合法性 if (numbat <0 || numbat >=14 || numtype <0 || numtype >=10) { printf("Invalid index: numbat=%d, numtype=%d\n", numbat, numtype); continue; } // 检查路径长度,避免缓冲区溢出 if (strlen(path) >=29) { printf("Path too long: %s\n", path); continue; } strcpy(monde->tabbatiment[numbat].tabpath[numtype], path); monde->tabbatiment[numbat].size.x = x; monde->tabbatiment[numbat].size.y = y; monde->tabbatiment[numbat].numtype = numtype; printf("Saved data: %d %d %d %d %s\n", numbat, monde->tabbatiment[numbat].size.x, monde->tabbatiment[numbat].size.y, monde->tabbatiment[numbat].numtype, monde->tabbatiment[numbat].tabpath[numtype]); } fclose(f);
内容的提问来源于stack exchange,提问作者Adel El HOUSNY
相关产品推荐
相关产品推荐

