返回一个二维数组或指向二维数组的指针

3
如果在函数内部创建了一个二维数组int 2DRepresentation[mapWidth][mapHeight];,那么最好的返回方法是什么?
函数的返回形式是什么?
是否更好地创建一个指向二维数组的指针,并将其传递到函数中,在函数中进行修改?如果是这样,那么指向二维数组的指针会是什么样子?像这样:int *2DRepresentation[mapWidth][mapHeight];
接受指向二维数组的指针的函数参数应该是什么样子的?
4个回答

2
如果在函数内创建一个 2D 数组 "int 2DRepresentation[mapWidth][mapHeight];",最好的返回方法是什么?
如果它像您表示的那样在函数内部创建(假设 mapWidth、mapHeight 是常量),则不应该返回它。因为它驻留在栈上并在函数返回时超出作用域,并且返回其引用只会指向垃圾。
是否更喜欢创建一个指向 2D 数组的指针并将其传递到函数中,在函数中修改它?
是的,你是正确的。
接受 2D 数组指针的函数参数应该是什么样的?
例如:
void foo( int twoDimensionalArray [][3] )
{

    // Now you can modify the array received.

}

int main()
{
     int ar[3][3] ;
     foo(ar) ;
     // .....
}

或者你可以在 foo 中动态分配内存并返回其引用。

int** foo()
{
    // ....
    return mallocatedTwoDimensionalArray ;
}

那么你需要复制它并返回该副本,或者你可以一开始就使用 malloc 分配该数组。 - Roland Illig
但是,如果传递的数组不是指针,它会被复制吗?最好的方法是创建一个可以在程序中传递的二维数组。 - some_id
@Helium3 - 这不是复制。当传递到函数时,2D数组会衰减为指向1D数组的指针。在传递数组时,不会进行复制。只是传递引用。 - Mahesh

2
你需要返回数组的基地址,即一个指针。然而唯一的解决方案是将数组变为静态,否则一旦函数超出作用域,它就会被销毁。如果你不想将其设为静态,你应该使用动态内存分配。
示例伪代码:
    int **array; // array is a pointer-to-pointer-to-int
    array = malloc(mapHeight * sizeof(int *));
    if(array == NULL)
        {
        fprintf(stderr, "out of memory\n");
        exit or return
        }
    for(i = 0; i < mapHeight ; i++)
        {
        array[i] = malloc(mapWidth * sizeof(int));
        if(array[i] == NULL)
            {
            fprintf(stderr, "out of memory\n");
            exit or return
            }
        }

这是如何将其传递给名为foo的函数的示例:
foo(int **array, int _mapHeight, int _mapWidth)
    {
    }

数组会退化为指针,因此您需要将行和列的值作为单独的参数传递。


array = malloc(mapHeight * sizeof(int *)); 这里使用malloc函数分配了数组的高度,那么宽度需要在其他地方分配吗? - some_id
释放数组时,是否需要迭代以释放宽度整数,还是可以一次性释放数组? - some_id
1
是的,你需要以迭代的方式释放它。 - Sadique

2
为了使数组在内存中持久存在,它要么需要被声明为static,要么应该使用malloccalloc进行显式分配(每种解决方案都有功能上的影响——即static版本将在下一次调用函数时被覆盖,而分配的版本需要在后面明确释放以避免内存泄漏)。
请注意,在C语言中,指针和数组并不相同。由于在malloc情况下处理动态分配,因此您将使用指针。使用这些指针引用数组元素在功能上与引用数组元素相同,因此一旦创建了数组,您不应该注意到任何区别。
以下是一个示例,它使用单个malloc来分配、填充和返回2D数组(既为了效率,也为了允许使用单个free进行释放):
int **get2dArray(int rows, int cols)
{
    int **array2d;
    int i, j, offset;
    int *gridstart;

    offset = rows * sizeof(int *);

    array2d = malloc( offset + rows*cols*sizeof(int) );

    /* Demote to char for safe pointer arithmetic */
    gridstart = (int *)((char *)array2d + offset); 

    for ( i = 0; i < rows; i++ ) {
        /* Point to the proper row */
        array2d[i] = gridstart + i*cols;

        /* Populate the array -- your code goes here */
        for ( j = 0; j < cols; j++ ) {
            array2d[i][j] = i*cols + j;
        }
    }

    return array2d;
}


int main ( int argc, char **argv )
{
   int **testarray;

   testarray = get2dArray( 10, 100 );

   /* Verify that addressing and population went as planned */
   printf( "%d %d %d %d %d %d\n", testarray[0][0], testarray[2][55], 
           testarray[4][98], testarray[5][0], testarray[7][15], 
           testarray[9][99] );   

   free(testarray);

   return 0;
}

有许多其他方法可以实现这一点,但这演示了一个将返回2D指针“数组”的函数。


1
最好在函数外定义数组并将其传递进去。
请记住,当数组用作函数参数时,它会衰减为指向其第一个元素的指针,因此在函数内部,它是一个指针,并且没有关于原始大小的信息。您还需要传递大小。
如果您有C99编译器,则可以使用“可变修改参数”(参见6.7.5.3):
int func(int rows, int cols, int data[rows][cols]) {
    int sum = 0;
    for (int row = 0; row < rows; row++) {
        for (int col = 0; col < cols; col++) {
            sum += data[row][col];
        }
    }
    return sum;
}

并且可以使用以下方式进行调用:

int main(void) {
    int a[42][100] = {0};
    if (func(42, 100, a) == 0) /*ok*/;

    int b[1000][2] = {0};
    if (func(1000, 2, b) == 0) /*ok*/;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接