C语言 分配和释放指向数组的指针数组的正确方法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17033315/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 06:39:32  来源:igfitidea点击:

Correct way to allocate and free arrays of pointers to arrays

carrayspointers

提问by Stas Jaro

I want to create an array of pointers to arrays of 3 floats. What is the correct way to do this?

我想创建一个指向 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));
}

Then how would I free the data? I'm pretty sure just free(array1);wouldn't work, so would I free each pointer in the array then free the array, or since I allocated three floats, would I free each float, then each 3 float array, then the whole array???

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

采纳答案by Dariusz

A general rule is that for each time you call malloc()or calloc()you will need to do a free()call on the returned pointer.

一般的规律是,每次你打电话malloc()calloc()你需要做一个free()对返回的指针调用

If you want a two dimensional array with compile-time known size, just use a two dimensional array! float val[5][3]is perfectly valid.

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

If you want a two dimensional array and you don't know it's size during compile-time, you most probably want to use a standard, single diemensional calloc() and an appropriate getter.

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

Of course replace the defines with appropriate variables.

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

By doing so you will:

通过这样做,您将:

  • save yourself costly allocs and frees
  • have less fragmented memory
  • simplify your possible realloc calls
  • ensure the data is cached better and accessed without the common [x][y] vs [y][x] iteration cache problem.
  • 为自己节省昂贵的分配和释放
  • 内存碎片较少
  • 简化您可能的重新分配调用
  • 确保数据得到更好的缓存和访问,而不会出现常见的 [x][y] 与 [y][x] 迭代缓存问题。

回答by alexis

If you know the array size at compile time (and you do, if SIZEis a compile-time constant), you should just declare a two-dimensional array. You don't need to free this at all (and must not).

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

float array1[SIZE][3];

You need to use calloc, and to create an array of pointers, only if the dimensions are not known at compile time. In this case, there should be one call to freefor each call to calloc. And since you cannot use an array after you free it, you need to free the row arrays before you free array1.

您需要使用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);

Edit:if you won't be rearranging the pointers (to sort the rows in-place, for example), you can do all of this with just one calloc(and one call to freeafterwards):

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

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

That's because the number of columnsis known at compile-time, and that's all the pointer arithmetic needs to know. Then you can write things like array1[i][j], and you can still pass around array1[i]as if it was a real pointer to a row. C is great that way, take advantage of it!

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

回答by Porkbutts

I want to create an array of pointers to arrays of 3 floats. What is the correct way to do this?

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

Why do you want an array of pointers to arrays? Wouldn't an array of arraysbe sufficient? (Keep in mind that arrays are already pointer-like, they are not passed by value, rather the address of the first element is passed when an array is passed as an argument to a function).

你为什么想要一个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]
}

Then how would I free the data?

那我该如何释放数据呢?

In this case you wouldn't, since the data is stack allocated (will be cleaned up automatically once out of scope). Just remember the rule of thumb is that for every memory allocation you make, a corresponding free is necessary. So if you allocate memory for an array of floats, as in

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

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

Then you only need to call free on the array that you malloc'd, no need to free the individual floats. If you perform nested allocation as in

然后你只需要在你的数组上调用 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);

Then you will need to perform a freefor every malloc, as in

然后你需要执行 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);

The lesson to take away here is to avoid dynamic allocation of arrays all-together. Stick with either std::vectoror stack-allocated arrays.

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