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

如何在结构体数组中分配字符串数组?程序崩溃问题排查

结构体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);

问题根源

  1. 内层循环下标错误:两次分配内存时,内层循环都错误使用外层的i作为tabpath的下标,而非内层的y。这会导致:
    • 每次内层循环都覆盖tabpath[i]的地址,其他下标(0到i-1、i+1到9)的指针要么未初始化(malloc版本),要么为NULL(calloc版本)
    • 当i >=10时,tabpath[i]会越界访问,破坏内存结构
  2. 数组越界访问:
    • 仅分配了14个建筑的tabpath,但读取文件时循环16次,若numbat取值超过13,会越界访问tabbatiment数组
    • numtype若超过9,会越界访问仅分配了10个指针的tabpath
  3. 变量未初始化: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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 06:15:38