【问题标题】:C pass variable size 2-D array to functionC将可变大小的二维数组传递给函数
【发布时间】:2017-07-26 21:19:24
【问题描述】:

我正在尝试重构我的代码以使其更好/更具可读性,因此我正在尝试更改二维变量数组分配,如下所示

// OLD CODE
int **map;
        map = calloc(number, sizeof(int *));
        if (!(map)) {
            free(map);
            return 1;
        }
        for (int i = 0; i < number; i++) {
            map[i] = calloc(number, sizeof(int));
            if (!(map[i])) {
                while (--i >= 0) {
                    free(map[i]);
                }
                free(map);
                return 1;
            }
        }

// NEW CODE
int (*map)[number] = malloc(sizeof (int[number][number]));
if (!(map)){
    free(map);
    return 1;
}

问题是我所有使用 map 的函数都采用 int **map 并像我所做的那样更改 map 的声明,IDE 告诉我 incorrect type int[]* instead of int** 我应该用什么来代替int**?在函数声明中使用int[]* map 告诉我can't resolve variable map

【问题讨论】:

  • type func(int n, int (*map)[n]); 致电func(number, map);
  • 帮自己一个忙,只需创建一个平面数组,然后通过 array[y*width+x] = value; 引用行
  • @MalcolmMcLean 我在想,有没有办法分配一半的地图大小而不必担心索引的顺序?在我的地图位置 [i][j] 和 [j][i] 将始终具有相同的值,但现在我分配所需大小的两倍,而不必担心 i 和 j 的顺序。
  • 要清楚,新代码map 不是二维数组。它是一个“指向 int 数组编号的指针”。旧的mappointer to pointer to int
  • 顺便说一句:为什么calloc((number - 1), sizeof(int *)) 中的 -1?当然旧代码与以下for (int i = 0; i &lt; number; i++) { map[i] = calloc(number, sizeof(int));... 不正确

标签: c malloc


【解决方案1】:

在标准代码unlike the other answer 中使用一个分配有点棘手,因为需要确保指针和int 的组合内存分配需要满足int 对齐要求的不寻常情况下的对齐问题超过指针对齐的。这更容易用long long 显示,如下所示。

如果这让“代码更易于阅读”留给 OP 判断。

#include <stdlib.h>
#include <stdio.h>

long long **map_allocate_ll(size_t row, size_t column) {
  long long  **map;
  long long  *ints;

  size_t pointers_sz = sizeof *map * row;
  // extend pointer size to `*ints` boundary
  pointers_sz = (pointers_sz + sizeof *ints - 1)/sizeof *ints * sizeof *ints;
  size_t ints_sz = sizeof *ints * row * column;
  printf("psize %zu, isize %zu\n", pointers_sz, ints_sz);

  map = calloc(1, pointers_sz + ints_sz);
  if (map == NULL) {
    return NULL;
  }
  ints = (void*) ((char*) map + pointers_sz);
  printf("map    %p\n", (void *) map);
  for (size_t i = 0; i<row; i++) {
    map[i] = &ints[i * column];
    printf("map[%zu] %p\n", i, (void *) map[i]);
  }
  return map;
}

int main() {
  free(map_allocate_ll(5,3));
}

样本输出

psize 24, isize 120
map    0x80081868
map[0] 0x80081880
map[1] 0x80081898
map[2] 0x800818b0
map[3] 0x800818c8
map[4] 0x800818e0

【讨论】:

    【解决方案2】:

    原来下面的代码不是 C99 替代 @M.M,而是 GCC 扩展。

    Undocumented GCC Extension: VLA in struct


    作为 C99 GCC 扩展替代 int (*map)[number] = malloc(sizeof (int[number][number])); 以简化代码并保持与现有函数集的兼容性,通过 1 个 *alloc() 调用分配所需的所有内存。

    这确实要求当使用map 完成代码时,所有内存都被一个free(map) 释放。此外,map[] 的各个行不能再重新分配,但可以在 map[] 内交换。

    int **map_allocate(size_t row, size_t column) {
      struct {
        int *ip[row];        // Array of pointers, followed by a ...
        int i[row][column];  // 2D array of int
      } *u;
      u = calloc(1, sizeof *u);
      if (u == NULL) {
        return NULL;
      }
      for (size_t i = 0; i<row; i++) {
        u->ip[i] = u->i[row];
      }
      return &u->ip[0];
    }
    

    注意:没有转换和字段 i[][] 正确对齐。

    【讨论】:

    • 结构不能包含 VLA
    • @MM 有趣。然而u 这里不是struct,而是指向一个的指针——但我希望这不会产生足够的差异。一个编译器接受了它(警告很好地启用了 - 或者我认为 - 因此这篇文章)和另一个警告,正如你所说,“结构或联合的成员不能有可变修改的类型”。我会复习的。
    • @M.M 看来我又回到了绘图板上。太糟糕了,它看起来确实是个不错的解决方案。
    猜你喜欢
    • 1970-01-01
    • 2011-05-24
    • 1970-01-01
    • 1970-01-01
    • 2021-05-10
    • 1970-01-01
    相关资源
    最近更新 更多