2012-02-25 102 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