【问题标题】:Dynamically allocate a string matrix in C在C中动态分配字符串矩阵
【发布时间】:2012-02-11 23:27:26
【问题描述】:

我正在尝试从文本文件中读取地图并根据地图中的行数和列数创建一个字符串数组。网格中的每个单元格都是一个 2 个字符的字符串。

例如,

**--**--**--
--**--**--**

应该创建一个 2*6 矩阵。行数和列数分别为 ROWS 和 COLS。我用过

char ***map = malloc(ROWS * sizeof(char *));
for (i = 0; i < ROWS; i++) 
{
    map[i] = malloc(COLS * sizeof(char) *  2);
}

但是当我尝试使用map[x][y] 时,它会出现段错误。

【问题讨论】:

    标签: c matrix memory-management malloc


    【解决方案1】:

    char ***map; 可以解释为“字符串数组的数组”,因此内部数组实际上包含 char 指针。因此,您的循环需要如下所示:

    for(i = 0; i < ROWS; i++) {
        int j;
    
        map[i] = malloc(COLS * sizeof(char*));
        for(j = 0; j < COLS; j++) map[i][j] = malloc(3 * sizeof(char)); // 3 chars because a string has to be terminated by \0
    }
    

    或者,您可以将 map 声明为 char **map,然后您的初始化代码将起作用,但是您需要使用 map[i][j]map[i][j+1] 来访问各个单元格的元素。

    【讨论】:

    • 试过这个,现在没有段错误,但现在看起来数组是空的,或者由于某种原因它没有打印任何东西。似乎不是我将文件读入数组的方式。 pastebin.com/8Uu4fNJf
    • 呃,手动填充了数组,看起来现在正在打印。好吧,我想我应该解决阅读问题。
    • 关于阅读问题:我用fgets统计了map的行数和列数,当然一直到EOF。所以我不得不通过关闭并重新打开文件来重新启动指针位置,但我认为应该有一种更有效的方法。
    • @user1002327 这就是fseek(或者在你的特殊情况下,rewind)的用途。
    【解决方案2】:

    它可能看起来像这样:

    int i, j, ROWS = 2, COLS = 6;
    char ***map = malloc(ROWS * sizeof(char **));
    for (i = 0; i < ROWS; ++i)
    {
       map[i] = malloc(COLS * sizeof(char*));
       for (j = 0; j < COLS; ++j)
          map[i][j] = malloc(2 * sizeof(char));
    }
    

    请注意,2 chars 允许您存储这些字符,但如果您要将它们作为字符串使用(printf("%sstrcpy ...),可能会给您带来一些麻烦。在这种情况下,我宁愿为 3 个chars 分配内存,以便也可以存储终止字符。

    还请注意,一旦分配了此内存,就应该清理它,并且清理应该根据分配以相反的顺序进行。它可能看起来像这样:

    for (i = 0; i < ROWS; ++i)
    {
       for (j = 0; j < COLS; ++j)
          free(map[i][j]);
       free(map[i]);
    }
    free(map);
    

    希望这会有所帮助。

    【讨论】:

    • 如果你知道每个字符串只有2个字符,你不一定需要第3个字符。
    • @RichardJ.RossIII:是的,2 个字符足以存储它们。但是,如果他想打印它们怎么办?如果有终止字符,他不需要编写自己的打印函数......
    • @RichardJ.RossIII :无论如何,这是一个好点。我已经编辑了我的答案。
    【解决方案3】:

    应该是

    char ***map = malloc(ROWS * sizeof(char**));
    for (i = 0; i < ROWS; i++) 
    {
       map[i] = malloc(COLS * sizeof(char*));
       for (int j=0; i<COLS; ++j)
          map[i][j] = malloc(3*sizeof(char);
    }
    

    编辑:正如在另一个答案和评论中指出的那样,应该是 3 而不是 2 malloc'ed chars。

    【讨论】:

    • 但是如果您事先知道每个条目是 2 个字符,您可能只想将其设为 unsigned shorts 的矩阵并在必要时重新解释,这可能总体上不那么烦人。
    • malloc 三个字符可能会更好,两个用于字符串字符,一个用于空终止符。
    • @user1002327 在哪里?并在最后一行尝试使用 3 而不是 2(参见上面的编辑)。
    【解决方案4】:

    第一行应该是:

    char **map = malloc(ROWS * sizeof(char *));
    

    根据经验,将* 添加到 malloc() 的返回类型。如果你用malloc(5 * sizeof(int)) 分配一个由五个整数组成的数组,那么你会得到一个int *

    或者,您可以将每个 * 视为添加一个维度 - char * 是一维字符数组,char ** 是一个二维数组。

    【讨论】:

      【解决方案5】:

      如果你想要二维数组,你如何将map 声明为char***?将其更改为char**

      (如果我误会了,你想要char*的二维数组,你应该改变分配,使用sizeof(char**)sizeof(char*),并分别为字符串分配内存。)

      编辑:如果您在声明地图时知道地图的大小,请将其设为char map[ROWS][COLS][2]; 如果您不这样做(或者您只想将其传递给其他函数),您可以将其声明为 char (**map)[2],并保持分配不变。

      (如果您想通过\0 终止它们,请将2 更改为3(例如打印))

      【讨论】:

      • 这是一个二维字符串数组,所以我添加了额外的 *.我会看看char**会发生什么。
      • 别忘了给字符串分配内存!
      • Sizeof char ** 和 sizeof char * 在整个系统中是等效的。一种指针类型的大小始终与另一种相同。
      • @RichardJ.RossIII 一般来说,2 种指针类型可能有不同的大小。在这种情况下有什么特别的吗?
      • @asaelr 不,我的意思是内存块的地址总是相同的大小(通常在 32 位系统上为 32 位,在 64 位系统上为 64 位)。然而,地址实际指向的是另一回事。
      猜你喜欢
      • 2018-01-29
      • 1970-01-01
      • 2023-03-03
      • 1970-01-01
      • 1970-01-01
      • 2021-10-13
      • 1970-01-01
      • 2018-04-24
      • 2016-09-12
      相关资源
      最近更新 更多