11

我想创建一个指向 3 个浮点数组的指针数组。这样做的正确方法是什么?

float *array1[SIZE]; // I think it is automatically allocated
// OR
float **array1 = calloc(SIZE, sizeof(float*));
free(array1);

for (int i = 0; i < SIZE; i++) {
    array1[i] = (float[]){0,0,0};
    // OR
    array1[i] = calloc(3, sizeof(float));
}

那么我将如何释放数据?我很确定这free(array1);是行不通的,所以我会释放数组中的每个指针然后释放数组,还是因为我分配了三个浮点数,我会释放每个浮点数,然后每个 3 个浮点数数组,然后是整个数组? ?

4

3 回答 3

4

如果您在编译时知道数组大小(并且您知道,如果SIZE是编译时常量),您应该只声​​明一个二维数组。你根本不需要释放它(而且绝对不能)。

float array1[SIZE][3];

您需要使用calloc, 和 创建一个指针数组,只有在编译时维度未知的情况下。free在这种情况下,每次调用都应该有一个调用to calloc。而且由于释放后无法使用数组,因此需要在释放之前释放行数组array1

float **array1 = calloc(nrows, sizeof (float *));
for (int i=0; i < nrows; i++)
    array1[i] = calloc(3, sizeof(float));
// Use it...

// Now free it
for (int i=0; i < nrows; i++)
    free(array1[i]);
free(array1);

编辑:如果您不重新排列指针(例如,对行进行就地排序),您只需一个calloc(然后再调用一次)即可完成所有这些操作free

float (*array1)[3] = calloc(3*nrows, sizeof (float));

这是因为数在编译时是已知的,而这就是指针算法需要知道的全部。然后你可以写类似的东西array1[i][j],你仍然可以传递,array1[i]就好像它是一个真正的指向行的指针。C 就是这样很棒,好好利用它!

于 2013-06-10T21:48:45.193 回答
2

我想创建一个指向 3 个浮点数组的指针数组。这样做的正确方法是什么?

你为什么要一个array of pointers to arrays?一个array of arrays还不够吗?(请记住,数组已经类似于指针,它们不是按值传递的,而是在将数组作为参数传递给函数时传递第一个元素的地址)。

// stack allocation, no need to free
float array[SIZE][3]; 

for (int i = 0; i < SIZE; i++) {
    // do something with array[i][0], array[i][1], array[i][2]
}

那么我将如何释放数据?

在这种情况下你不会,因为数据是堆栈分配的(一旦超出范围就会自动清理)。请记住,经验法则是,对于您进行的每个内存分配,都需要相应的空闲空间。因此,如果您为浮点数组分配内存,如

float* arr = malloc(sizeof(float) * 3); // array of 3 floats

然后你只需要在你的数组上调用 free malloc'd,不需要释放单个浮点数。如果您执行嵌套分配,如

// array of length SIZE, consisting of float pointers
float** arr = malloc(sizeof(float*) * SIZE);

// allocate the array of 3 floats at each index
for (int i = 0; i < SIZE; i++) 
    arr[i] = malloc(sizeof(float) * 3);

然后您将需要执行 a freefor each malloc,如

// free the individual arrays
for (int i = 0; i < SIZE; i++)
    free(arr[i]);
// free the array of arrays
free(arr);

这里要吸取的教训是避免一起动态分配数组。坚持使用其中一个std::vector或堆栈分配的数组。

于 2013-06-10T21:47:55.610 回答
2

一般规则是,每次调用时malloc()calloc()您都需要对free()返回的指针进行调用

如果你想要一个编译时已知大小的二维数组,只需使用二维数组!float val[5][3]是完全有效的。

如果您想要一个二维数组并且在编译时不知道它的大小,您很可能想要使用标准的单维 calloc() 和适当的 getter。

#define ARR_COLUMNS 10
#define ARR_ROWS 10
float* arr = calloc (ARR_COLUMNS * ARR_ROWS, sizeof(float));

int get(float* arr, int x, int y) {
  if (x<0 || x>= ARR_COLUMNS) return 0;
  if (y<0 || y>= ARR_ROWS) return 0;
  return arr[ARR_COLUMNS*y+x];
}

void set (int* arr, int x, int y, float val) {
  if (x<0 || x>= ARR_COLUMNS) return;
  if (y<0 || y>= ARR_ROWS) return;
  arr[ARR_COLUMNS*y+x] = val;
}

当然用适当的变量替换定义。

通过这样做,您将:

  • 为自己节省昂贵的分配和释放
  • 内存碎片较少
  • 简化您可能的 realloc 调用
  • 确保数据被更好地缓存和访问,而没有常见的 [x][y] vs [y][x] 迭代缓存问题。
于 2013-06-10T21:57:11.883 回答