在C中动态分配数组的函数——两者之间有什么区别



假设你在C中有一个函数,它接受2d数组的维度(为了简单起见,比如正方形的nxn数组),动态分配数组,然后返回它。

我知道在这里分配内存一开始可能会被认为是一种不好的做法,因为它需要在其他地方释放,但假设这不是一个大问题。我想知道上述功能的这两种变体是否有任何优点/缺点:

变体1-在函数中本地定义int**变量,分配/返回数组:

int **create_array(int n) {
// define array pointer, allocate array...
int **a_ = (int**)calloc(n,sizeof(int*));
for (int i = 0; i < n; i++) 
a_[i] = (int*)calloc(n,sizeof(int));
return a_;
}
int main() {
int n = 3;
int **array2d = create_array(n)
printf("First element: %d%c",array2d[0][0],'n');
// do stuff... etc...
}

变体2-将int**参数添加到函数,分配/返回数组:

int **create_array_2(int **a_, int n) {
// allocate array...
a_ = (int**)calloc(n,sizeof(int*));
for (int i = 0; i < n; i++) 
a_[i] = (int*)calloc(n,sizeof(int));
return a_;
}
int main() {
int n = 3;
int **array2d;
array2d = create_array_2(array2d,n);
printf("First element: %d%c",array2d[0][0],'n');
// do other stuff... etc...
}

显然,他们得到了相同的结果,完成了相同的任务,但其中一个被认为比另一个更安全/更有效率/更好的实践吗?在我看来,第二个变体只是让事情看起来有点多余,但我很好奇这两者之间是否有真正的区别,以及调用它们时堆栈/堆上会发生什么。希望这不是一个愚蠢的问题;这只是我一直好奇的事情。如果有人有真知灼见可以分享,我将不胜感激。

我可能会尽量避免多次调用mallocfree,所以我将采用这种方法:

示例1:

#include <stdio.h>
#include <stdlib.h>
int *foo(size_t row, size_t col);
int main(void){
int *arr;
unsigned int row, col, k;
printf("Give the ROW: ");
if ( scanf("%u",&row) != 1){
printf("Error, scanf ROWn");
exit(1);
}
printf("Give the COL: ");
if ( scanf("%u",&col) != 1){
printf("Error, scanf COLn");
exit(2);
}
arr = foo(row, col);
for (k = 0 ; k < (row * col) ; k++){
printf("%d ",arr[k]);
}
free(arr);
}
int *foo(size_t row, size_t col){
unsigned int i, j;
int *arr = malloc(sizeof *arr * row * col);
int l = 0;
if(arr == NULL){
printf("Error, mallocn");
exit(3);
}
for ( i = 0; i < row ; i++){
for ( j = 0 ; j < col ; j++){
arr[i * col + j] = l;
l++;
}
}
return arr;
}

输出:

Give the ROW: 6
Give the COL: 3
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17

示例2(如果您使用的是标准C):

#include <stdio.h>
#include <stdlib.h>
int (*foo(size_t row, size_t col))[];
int main(void){
size_t row, col;

printf("Give the ROW: ");
if ( scanf("%zu",&row) != 1){
printf("Error, scanf ROWn");
exit(1);
}
printf("Give the COL: ");
if ( scanf("%zu",&col) != 1){
printf("Error, scanf COLn");
exit(2);
}
int (*arr)[col] = foo(row, col);
for ( size_t i = 0; i < row; i++){
for( size_t j = 0; j < col; j++){
printf("%d ",*(*(arr+i)+j));
}
}
free(arr);
}
int (*foo(size_t row, size_t col))[]{
int (*arr)[col] = malloc(row * col * sizeof(int));
int l=0;
if (arr == NULL){
printf("Error, mallocn");
exit(3);
}
for ( size_t i = 0; i < row; i++){
for( size_t j = 0; j < col; j++){
*(*(arr+i)+j) = l;
l++;
}
}
return arr;
}

输出:

Give the ROW: 6
Give the COL: 3
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17

这里的重点是,两个例子中的mallocfree的调用只发生一次

IMO,在这两者中,您最好简单地返回值。这样,在你和打电话的人之间就有了一堵纯净而坚固的墙。

"给我一些东西">

"好吧,这里有一些东西">

另一方面,对于实际分配固定大小的数组,为什么要使用指针呢?为什么不声明您的返回类型,以便可转换为一个大小合适的数组呢?

int (*p2a)[15] = (int(*)[15])create_array_2(15, 15);

然后你就calloc(15*15,sizeof(int))了。

最新更新