正确的方法来分配和释放指向数组的指针

时间:2013-06-10 21:40:15

标签: c arrays pointers

我想创建一个指向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浮点数组,然后整个阵列???

3 个答案:

答案 0 :(得分:4)

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

float array1[SIZE][3];

只有在编译时不知道维度时,才需要使用calloc并创建指针数组。在这种情况下,每次拨打free都应该拨打一次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));

那是因为 columns 的数量在编译时是已知的,并且这是所有指针算术需要知道的。然后你可以写array1[i][j]这样的东西,你仍然可以传递array1[i],好像它是一个真正的指针。 C很棒,利用它!

答案 1 :(得分:2)

  

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

为什么要array of pointers to arraysarray 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

然后你只需要在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);

然后,您需要为每个free执行malloc,如

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

这里要取消的教训是避免将数组全部动态分配。坚持使用std::vector或堆栈分配的数组。

答案 2 :(得分:2)

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

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

如果你想要一个二维数组并且在编译时你不知道它的大小,你很可能想要使用一个标准的,单个的dieca()和一个合适的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;
}

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

通过这样做,您将:

  • 节省自己昂贵的分配和释放
  • 内存碎片较少
  • 简化您可能的重新分配电话
  • 确保数据更好地缓存并在没有常见[x] [y] vs [y] [x]迭代缓存问题的情况下访问。