将二维数组传递给函数的正确方法

时间:2012-02-25 18:20:30

标签: c

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

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

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

6 个答案:

答案 0 :(得分:69)

你应该声明你的功能:

void display(int p[][numCols])

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

答案 1 :(得分:13)

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

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

答案 2 :(得分:6)

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

#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);
}

答案 3 :(得分:5)

有几种,有时是等效的方法。通过使用指针(参见method_c())或使用指向数组数组的指针(参见method_b())来声明一个数组(参见method_a())。使用单个指针的method_b()稍微难以正确,因为使用标准数组索引并不容易,因此我们使用指针算法。 method_a()method_c()基本相同,因为数组在编译期间非递归地衰减到指针。这是一个小程序,说明了所有三种方法。我们首先在一个简单的for循环中初始化2x4 - 数组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;
        }
    }
}

答案 4 :(得分: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(我不喜欢顺便说一句)

,这个特别有意思
 typedef int matrix[5][6];

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

答案 5 :(得分:0)

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

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

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

实际上,指针需要知道每一行的大小。这对指针算法非常重要。因此,当您递增指针时,指针必须指向下一行。

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

在主要内容中,您无需进行任何更改。 display(arr)很好。