在C语言中传递多维数组作为函数参数

55
在C语言中,当我不知道数组的维度时,是否可以将一个多维数组作为单个参数传递给函数?此外,我的多维数组可能包含除字符串以外的其他类型。
5个回答

36

传递一个明确的指向第一个元素的指针,将数组维度作为单独的参数传递。例如,要处理任意大小的int二维数组:

void func_2d(int *p, size_t M, size_t N)
{
  size_t i, j;
  ...
  p[i*N+j] = ...;
}

这将被称为

...
int arr1[10][20];
int arr2[5][80];
...
func_2d(&arr1[0][0], 10, 20);
func_2d(&arr2[0][0], 5, 80);

对于高维数组,同样适用相同的原则:

func_3d(int *p, size_t X, size_t Y, size_t Z)
{
  size_t i, j, k;
  ...
  p[i*Y*Z+j*Z+k] = ...;
  ...
}
...
arr2[10][20][30];
...
func_3d(&arr[0][0][0], 10, 20, 30);

2
p[i*Y+j*Z+k] 应该改为 p[i*Y*Z+j*Z+k] - David H
https://dev59.com/uHLYa4cB1Zd3GeqPdvcp - Dchris
i和j的值是多少? - AlphaGoku
非常感谢您的回答,@John Bode。您能否解释一下为什么要使用p[i*N+j]来访问多维数组中的特定元素? - F. Zer
1
@F.Zer - 是的。在这个例子中,每行有两列。 - John Bode
显示剩余2条评论

24

您可以将函数声明为:

f(int size, int data[][size]) {...}

编译器将为您执行所有指针算术运算。

请注意,维度大小必须出现在数组本身之前

GNU C允许参数声明转发(在您确实需要在数组之后传递维度的情况下):

f(int size; int data[][size], int size) {...}

虽然你也可以将第一维作为参数传递,但对于C编译器来说它是无用的(即使是在sizeof操作符中,当应用于作为参数传递的数组时,它也总是将其视为指向第一个元素的指针)。


2
在我看来,这应该是被接受的答案。不需要额外的代码,也没有不必要的堆分配。简单而干净。 - kjh
感谢@kjh,我也认为这是最清晰的解决方案。被采纳的答案是对他起作用的答案。看:OP来自2008年,比我的回答早了将近6年。除此之外,我不知道当时C标准是否允许我在这里使用的语法。 - rslemos
这是我最终采用的解决方案,用于将大小为 M x N 的整数矩阵(即二维数组)作为函数参数传递。也许提供一点更多的信息会有帮助:函数的原型如下:void f(int N, int data[][N], int M); 在函数体中,元素 [m][n] 可以写作 data[m][n] - 非常方便,无需进行索引计算。 - jonathanzh
我按照你说的声明了函数,并从main()中调用它,一切都正常。但是如果我不知道大小,我该如何在main()中声明变量data?我尝试使用int* data,但不起作用。 - glc78
@glc78,可以将数据作为VLA存储在堆栈上int data[height][width];或者使用int (*data)[width] = malloc(height*sizeof(*data));在堆上进行存储。在这两种情况下,您都可以按照正常方式访问data[y][x]并将其传递给f(width, data) - cmaster - reinstate monica

23

你可以对任何数据类型进行这样的操作。只需将其指针改为指向指针:

typedef struct {
  int myint;
  char* mystring;
} data;

data** array;

但不要忘记您仍需为变量分配内存,这会变得有些复杂:

//initialize
int x,y,w,h;
w = 10; //width of array
h = 20; //height of array

//malloc the 'y' dimension
array = malloc(sizeof(data*) * h);

//iterate over 'y' dimension
for(y=0;y<h;y++){
  //malloc the 'x' dimension
  array[y] = malloc(sizeof(data) * w);

  //iterate over the 'x' dimension
  for(x=0;x<w;x++){
    //malloc the string in the data structure
    array[y][x].mystring = malloc(50); //50 chars

    //initialize
    array[y][x].myint = 6;
    strcpy(array[y][x].mystring, "w00t");
  }
}

释放该结构的代码看起来很相似 - 不要忘记调用free()释放你所分配的所有内存! (此外,在健壮的应用程序中,你应该检查malloc()的返回值。)

现在假设你想将其传递给函数。 你仍然可以使用双指针,因为你可能想对数据结构进行操作,而不是指向数据结构指针的指针:

int whatsMyInt(data** arrayPtr, int x, int y){
  return arrayPtr[y][x].myint;
}

使用以下方式调用此函数:

printf("My int is %d.\n", whatsMyInt(array, 2, 4));

输出:

My int is 6.

需要帮助,请前往以下链接:https://dev59.com/uHLYa4cB1Zd3GeqPdvcp - Dchris
6
指向指针段的查找表不是一个二维数组。仅仅因为它允许使用 [][] 语法,它并不能神奇地变成一个数组。你不能对其进行 memcpy() 等操作,因为内存不是在相邻的内存单元中分配的,这是数组所必需的。你的查找表会分散在堆上,使得查找变慢并且堆碎片化。 - Lundin

1
在C语言中,当我不知道数组的维度时,能否将多维数组作为单个参数传递给函数?答案是否定的。如果您指的是仅传递数组而不传递数组维度,则不能。至少对于真正的多维数组来说是这样的。您可以将维度与数组一起放入结构体中,并声称您正在传递一个“单个参数”,但那只是将多个值打包到单个容器中,并将该容器称为“一个参数”。您可以通过像这样传递维度本身和数组来传递已知类型和维度数量但未知大小的数组:
void print2dIntArray( size_t x, size_t y, int array[ x ][ y ] )
{
    for ( size_t ii = 0, ii < x; ii++ )
    {
        char *sep = "";
        for ( size_t jj = 0; jj < y; jj++ )
        {
            printf( "%s%d", sep, array[ ii ][ jj ] );
            sep = ", ";
        }
        printf( "\n" );
    }
}

你会这样调用该函数:

int a[ 4 ][ 5 ];
int b[ 255 ][ 16 ];

...

print2dIntArray( 4, 5, a );

....

printt2dIntArray( 255, 16, b );

同样地,例如一个struct pixel的三维数组:

void print3dPixelArray( size_t x, size_t y, size_t z, struct pixel pixelArray[ x ][ y ][ z ] )
{
    ...
}

或者是一个一维的 double 数组:
void print1dDoubleArray( size_t x, double doubleArray[ x ] )
{
    ...
}

但是...

然而,可以通过传递被错误标记为“多维数组”的“指向类型为X的指针数组的指针数组的指针数组......到一维X数组”的构造方式作为单个参数,只要基本类型X具有可用于指示最终、最低级别的单维X数组结束的哨兵值。

例如,传递给main()char **argv值是指向char指针数组的指针。初始的char *指针数组以NULL哨兵值结束,而由char *指针数组引用的每个char数组以'\0'字符值结束。

例如,如果您可以使用NAN作为哨兵值,因为实际数据永远不会是NAN,您可以像这样打印double **

void printDoubles( double **notAnArray )
{
    while ( *notAnArray )
    {
        char *sep = "";
        for ( size_t ii = 0;  ( *notAnArray )[ ii ] != NAN; ii++ )
        {
            printf( "%s%f", sep, ( *notAnArray )[ ii ] );
            sep = ", ";
        }

        notAnArray++;
    }
}

-2
int matmax(int **p, int dim) // p- matrix , dim- dimension of the matrix 
{
    return p[0][0];  
}

int main()
{
   int *u[5]; // will be a 5x5 matrix

   for(int i = 0; i < 5; i++)
       u[i] = new int[5];

   u[0][0] = 1; // initialize u[0][0] - not mandatory

   // put data in u[][]

   printf("%d", matmax(u, 0)); //call to function
   getche(); // just to see the result
}

https://dev59.com/uHLYa4cB1Zd3GeqPdvcp - Dchris
1
这不是一个二维数组,而是一个查找表。此外,它被标记为C。 - Lundin

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