SIGSEGV 将对象分配给动态二维矩阵

SIGSEGV assigning an object to a dynamic 2d matrix

我试图简单地将定义为 Card 的元素类型从一个向量分配给 mtr[i][j],一个存储在堆中的二维矩阵,但调试器声称存在分段错误。

我想我尝试了所有方法,尝试使用静态矩阵,检查监视 NULL,手动分配结构的每个成员。

出于好奇,我尝试将矩阵的类型更改为intchar。即便如此,分配(在正确更改要分配的值之后)不起作用。

int g_rows = 0, g_cols=0;

typedef struct{
    char color;
    int points;
}Segment;

typedef struct{
    Segment h;
    Segment v;
}Card;


Card** loadBoard(char* fileName, Card* cards) {
    short tileRef; short rot;
    short i=0;
    FILE* fp = fopen(fileName,"r"); if(fp == NULL) return NULL;
    if(fscanf(fp, "%hd %hd\n", &g_rows, &g_cols) == 0) {fclose(fp); return NULL;}
    
    Card **mtr = (Card**)malloc(g_rows * sizeof(**mtr)); if(!mtr){printf("Error on first malloc.\n");}
    for(short i = 0; i<g_rows; i++) {
        mtr[i] = (Card*)malloc(g_cols * (sizeof (*mtr)) );
        if(!mtr[i]) printf("error on 2nd malloc.\n");
    }
    i=0;
    while(!feof(fp)){
        for(short j=0;j<g_cols;j++) {
            fscanf(fp, "%d/%d\n", &tileRef, &rot);
            if (tileRef != -1)
                mtr[i][j] = (rot == 0) ? cards[tileRef] : (Card) {.h = cards[tileRef].v, .v = cards[tileRef].h};
            else
                mtr[i][j] = (Card){{.points=-1,.color='[=10=]'},{.points=-1,.color='[=10=]'}};
        }
        fscanf(fp,"\b\n"); i++;
    }
    fclose(fp);
    return mtr;
}

我试图搜索此类问题,但奇怪的是我最终研究了二维动态分配的代码示例。

也许我错过了一些重要的东西,但我真的抓不住。

最终编辑:我发现我使用的 che 编译器(Clang/LLVM 来自 MingW)是罪魁祸首。我尝试将 Visual Studio Community 设置为 CLion 中的默认工具链,但没有出现任何问题。

问题似乎是 malloc 调用中的细微拼写错误。

  1. 在矩阵的分配中,

    Card **mtr = (Card**)malloc(g_rows * sizeof(**mtr));
    

    malloc 正在为 g_rows * sizeof(Card) 分配 space。但是由于 mtr 被用来存储 Card 指针,而不是 Cards,所以我们需要 g_rows * sizeof(Card*).

  2. 然后在每个矩阵行的分配中,

    mtr[i] = (Card*)malloc(g_cols * (sizeof (*mtr)) );
    

    malloc 正在为 g_cols * sizeof(Card*) 分配 space。但是由于每个矩阵行都被用来存储卡片,而不是卡片指针,所以我们需要 g_cols * sizeof(Card)。这个错误特别严重,因为 sizeof(Card*) 小于 sizeof(Card),所以没有分配足够的内存。

在从文件中读取数据的while循环中,下面还有一个潜在的问题。只要文件继续,循环就会迭代,而不检查 i 变量是否仍在边界内。因此,如果文件格式不正确,可能会导致此代码注销矩阵的末尾和段错误。

评论:我强烈推荐使用 Valgrind or Address Sanitizer (ASan)。这些工具会自动检查与内存相关的错误,对于调试此类问题非常有用。