2012-02-25 99 views
46

我有一个2维数组,我将它传递给一个函数来执行某些操作。我想知道这样做的正确方法...将2维数组传递给函数的正确方法

#define numRows 3 
#define numCols 7 
#define TotalNum (numRows*numCols) 
int arr[numRows][numCols] = {{0,1,2,3,4,5,6}, {7,8,9,10,11,12,13},{14,15,16,17,18,19,20}}; 

void display(int **p) 
{ 
    printf("\n"); 
    for (int i = 0; i< numRows;i++) 
    { 
     for (int j = 0;j< numCols;j++) 
     { 
      printf("%i\t",p[i][j]); 
     } 
     printf("\n"); 
    } 
} 

int main() { 
    display(arr); 
} 

我得到一个错误信息:

'display': cannot convert parameter1 from 'int' to 'int*' 

这是传递一个2维数组到函数的正确方法?如果不是,那么正确的方法是什么?

+0

请参阅下面的答案。 – jupp0r 2012-02-25 18:23:24

+1

可能重复[C - 传递一个2d数组作为函数参数?](http://stackoverflow.com/questions/6862813/c-passing-a-2d-array-as-a-function-argument) – 2012-02-25 21:03:15

+0

小提示:对宏使用CAPS,这是常见的做法,可以让你的代码更清晰地告诉外部人员 – 2014-03-14 11:11:15

回答

67

应该声明你的功能是这样的:

void display(int p[][numCols]) 

这个C FAQ彻底解释了为什么。其要点在于,数组衰减为指针,一旦,它不会递归地发生。数组的数组衰减成指向数组的指针,而不是指向指针的指针。

+0

我有一个问题。这个函数是显示它,但如果它用来更改arr中的值? – lakesh 2012-02-25 19:22:56

+1

@lakesh它应该工作。 – cnicutar 2012-02-25 19:38:42

+0

@cnicutar,所以我们不能将int * [20]转换为int **。这是原因吗? – 2014-10-31 06:37:38

12

如果(就像你的情况一样),你知道编译时数组的维数,你可以只写void display(int p[][numCols])

一些解释:你可能知道,当你将一个数组传递给一个函数时,你实际上传递了一个指向第一个成员的指针。在C语言中,二维数组只是一个数组的数组。因此,您应该将函数传递给2D数组中的第一个子数组。所以,自然的方式就是说int (*p)[numCols](意思是 p是一个指针,指向一个数组numCols,整数)。在函数声明中,您有“快捷方式”p[],这意味着与(*p)完全相同(但告诉读者,您将指针传递给数组的开头,而不仅仅是一个变量)

+0

感谢您的解释.... – lakesh 2012-02-25 20:09:34

5

你正在做错的方式。您可以在指向数组的指针的帮助下传递二维数组,或者只传递一个数组或通过单指针。

#define numRows 3 
#define numCols 7 
void display(int (*p)[numcols],int numRows,int numCols)//First method// 
void display(int *p,int numRows,int numCols) //Second Method// 
void display(int numRows,int numCols,int p[][numCols]) //Third Method 
{ 
    printf("\n"); 
    for (int i = 0; i < numRows;i++) 
    { 
     for (int j = 0; j < numCols;j++) 
     { 
      printf("%i\t",p[i][j]); 
     } 
     printf("\n"); 
    } 
} 

int main() { 
    display(arr,numRows,numCols); 
} 
+2

宏与变量名冲突。 – Jarod42 2013-12-23 03:43:13

+3

方法2不编译。 – Jarod42 2013-12-23 03:52:02

+0

@Varun Chhangani - 作为他的答案中提到的lord.garbage,第三种方法在兼容C99的编译器中工作。 – 2017-10-07 18:00:53

0

声明它只是

void display(int (*p)[numCols][numRows]); 

这样你p指针传达所有必要的信息,并可以提取其中的所有尺寸,而不重复numColsnumRows一遍又一遍。

void display(int (*p)[numCols][numRows]) 
{ 
    size_t i, j; 

    printf("sizeof array=%zu\n", sizeof *p); 
    printf("sizeof array[]=%zu\n", sizeof **p); 
    printf("sizeof array[][]=%zu\n", sizeof ***p); 

    size_t dim_y = sizeof *p/sizeof **p; 
    printf("dim_y = %zu\n", dim_y); 

    size_t dim_x = sizeof **p/sizeof ***p; 
    printf("dim_x = %zu\n", dim_x); 

    for(i=0; i<dim_y; i++) { 
     puts(""); 
     for(j=0; j<dim_x; j++) 
     printf(" %6d", (*p)[i][j]); 
    } 
} 

,如果你使用typedef(我不喜欢BTW)

typedef int matrix[5][6]; 

在这种情况下,这是特别有趣的尺寸是不可见的函数的签名,但功能依然会具有正确的尺寸值。

0

如下可以改变显示方法的签名:

void display(int (*p)[numCols]) 

这里,p是一个指针到2D阵列的行。指针只需要知道数组中的列数。

其实说起来,指针需要知道每一行的大小。这对指针运算非常重要。所以当你增加指针时,指针必须指向下一行。

这里请注意,p不是一个正常的整数指针。这是一个指向内存大小等于integer_size x columns的整数指针。

主要你不需要改变任何东西。 display(arr)就好了。

3

有几种,有时候也是这样做的。通过声明一个数组(参见method_c()),使用指针(参见method_b())或使用指向数组数组的指针(参见method_a())。由于使用标准数组索引并不容易,所以使用单个指针稍微难以正确定位,因此我们使用指针算术。 method_a()method_c()基本上是等价的,因为数组在编译期间非递归地衰减到指针。这是一个说明所有三种方法的小程序。我们首先在一个简单的for循环中初始化一个2x4 -array arr并打印出来。它看起来像这样:

arr: 
0 1 2 3 
0 1 2 3 

然后我们调用所有三种方法。 method_a()增加1,method_b()增加2和method_c()增加3到所有元素。每次通话后,我们再次打印出阵列arr。如果一个功能正常工作,您将很容易在输出中看到它。大小是任意的,可以通过两个宏ROWCOL进行调整。最后一个注释method_c()C99起依赖于可变长度数组。

#include <stdio.h> 
#include <stdlib.h> 

#define ROW 2 
#define COL 4 

void method_a(int m, int n, int (*ptr_arr)[n]); 
void method_b(int m, int n, int *ptr_arr); 
void method_c(int m, int n, int arr[][n]); 

int main(int argc, char *argv[]) { 

    int arr[ROW][COL]; 

    int i; 
    int j; 
    for(i = 0; i < ROW; i++) { 
     for(j = 0; j < COL; j++) { 
      arr[i][j] = j; 
     } 
    } 

    printf("Original array:\n"); 
    for (i = 0; i < ROW; i++) { 
     for(j = 0; j < COL; j++) { 
      printf("%d\t", arr[i][j]); 
     } 
     printf("\n"); 
    } 

    printf("\n\n"); 

    method_a(ROW, COL, arr); 

    printf("method_a() array:\n"); 
    for (i = 0; i < ROW; i++) { 
     for(j = 0; j < COL; j++) { 
      printf("%d\t", arr[i][j]); 
     } 
     printf("\n"); 
    } 

    printf("\n\n"); 

    printf("method_b() array:\n"); 
    method_b(ROW, COL, (int *)arr); 

    for (i = 0; i < ROW; i++) { 
     for(j = 0; j < COL; j++) { 
      printf("%d\t", arr[i][j]); 
     } 
     printf("\n"); 
    } 

    printf("\n\n"); 

    method_c(ROW, COL, arr); 

    printf("method_c() array:\n"); 
    for (i = 0; i < ROW; i++) { 
     for(j = 0; j < COL; j++) { 
      printf("%d\t", arr[i][j]); 
     } 
     printf("\n"); 
    } 

    printf("\n\n"); 

    return EXIT_SUCCESS; 
} 

void method_a(int m, int n, int (*ptr_arr)[n]) 
{ 
    int i, j; 
    for (i = 0; i < m; i++) 
    { 
     for (j = 0; j < n; j++) 
     { 
      ptr_arr[i][j] = j + 1; 
     } 
    } 
} 

void method_b(int m, int n, int *ptr_arr) 
{ 
    int i, j; 
    for (i = 0; i < m; i++) 
    { 
     for (j = 0; j < n; j++) 
     { 
      /* We need to use pointer arithmetic when indexing. */ 
      *((ptr_arr + i * n) + j) = j + 2; 
     } 
    } 
    /* The whole function could have also been defined a bit different by taking 
    * the i index out of the pointer arithmetic. n alone will then provide our 
    * correct offset to the right. This may be a bit easier to understand. Our 
    * for-loop would then look like this: 
    * for (i = 0; i < m; i++) 
    * { 
    *  for (j = 0; j < n; j++) 
    *  { 
    *   *((ptr_arr + n) + j) = j + 2; 
    *  } 
    *  ptr_arr++; 
    * }*/ 
} 

void method_c(int m, int n, int arr[][n]) 
{ 
    int i, j; 
    for (i = 0; i < m; i++) 
    { 
     for (j = 0; j < n; j++) 
     { 
      arr[i][j] = j + 3; 
     } 
    } 
} 
+0

为什么我们在将数组传递给method_b()时需要做(int *)arr? – shane 2016-06-11 09:06:32

+0

@ lord.garbage +1,注意method_c()的C99问题。 – 2017-10-07 18:02:20

-1

对于上面的大多数答案,您需要知道至少不是。二维数组中的列。即使你通过了没有。函数本身中的列或声明否。全局列的一些编译器仍然可能会显示一些错误,并可能无法正常工作。 所以可以调用函数等

func((int **)a,r,c); 

其中a是2-d阵列,和r和c是没有。行和列分别。 你能赶上在功能这些数据作为

void func(int **a,int r,int c); 

,您可以通过使用指针,其中*((a+r*i)+j)会给你的a[i][j]值穿越它。

+0

欢迎来到SO,在你的答案中使用代码标记更有用。 – 2015-06-27 14:43:43

+0

不,你不能调用这样的函数。 – 2017-07-30 20:47:45