【问题标题】:Correct way of passing 2 dimensional array into a function将二维数组传递给函数的正确方法
【发布时间】:2012-02-25 18:20:30
【问题描述】:

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

#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*'

这是将二维数组传递给函数的正确方法吗?如果不是,正确的方法是什么?

【问题讨论】:

  • 小提示:使用 CAPS 作为宏,这是一种常见的做法,可以让你的代码对外人来说更清晰
  • 虽然这里问题的目的是了解如何将二维数组传递给函数,但要为上述示例添加正确性,arr 应该是 main 的本地。

标签: c


【解决方案1】:

你应该像这样声明你的函数:

void display(int p[][numCols])

C FAQ 彻底解释了原因。它的要点是数组衰减为指针一次,它不会递归地发生。数组数组衰减为指向数组的指针,而不是指向指针的指针。

【讨论】:

  • 我有一个问题。这个函数是用来显示它的,但是如果它用来改变arr中的值呢?
  • @cnicutar,所以我们不能将 int*[20] 转换为 int**。是这个原因吗?
【解决方案2】:

如果(如您的情况),您在编译时知道数组的维度,您可以只写void display(int p[][numCols])

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

【讨论】:

    【解决方案3】:

    你做错了。您可以通过指向数组的指针传递二维数组,或者简单地传递数组或通过单指针。

    #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无法编译。
    • @Varun Chhangani - 正如 lord.garbage 在他的回答中提到的,第三种方法适用于 C99 兼容的编译器。
    【解决方案4】:

    有几种,有时是等效的方法可以做到这一点。通过声明一个数组(参见method_c())、使用一个指针(参见method_b())或使用一个指向数组的数组的指针(参见method_a())。 method_b(),使用单个指针,稍微更难正确,因为使用标准数组索引并不容易,因此,我们使用指针算法。 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;
            }
        }
    }
    

    【讨论】:

    • 为什么我们在将数组传递给 method_b() 时需要做 (int *)arr?
    • @lord.garbage +1 关注 method_c() 的 C99 问题。
    【解决方案5】:

    简单地声明一下

    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(顺便说一句,我不喜欢它),这会特别有趣

     typedef int matrix[5][6];
    

    在这种情况下,维度在函数的签名中不可见,但函数仍将具有正确的维度值。

    【讨论】:

      【解决方案6】:

      您可以按如下方式更改显示方法的签名:

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

      这里,p 是指向二维数组行的指针。指针只需要知道数组中的列数。

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

      请注意,p 不是普通的整数指针。它是一个指向内存大小的整数指针,等于integer_size x columns

      在 main 中,您无需更改任何内容。 display(arr) 就好了。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-11-01
        相关资源
        最近更新 更多