将三维数组传递给C中的函数

时间:2016-11-28 13:17:46

标签: c arrays

我用FORTRAN编程,但我决定学习CC++。我从C语言开始,我从未使用的一件事是指针,因为FORTRAN通过引用传递值。我构建了下面的示例代码,以了解指针如何与多维数组一起使用:

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

#define DIM1 3
#define DIM2 2 
#define DIM3 4

void display3DArray1(int, int , int n, int (*arr)[][n]);
void display3DArray2(int rows, int cols1, int cols2,int arr[][cols1][cols2]);

int main(void)
{
    int matrix3D[DIM1][DIM2][DIM3] = {
        {{1, 2, 3, 4}, {5, 6, 7, 8}},
        {{9, 10, 11, 12}, {13, 14, 15, 16}},
        {{17, 18, 19, 20}, {21, 22, 23, 24}}
    };
    int (*pmatrix3D)[DIM2][DIM3] = matrix3D;

    display3DArray1(DIM1, DIM2, DIM3,pmatrix3D); 
    display3DArray2(DIM1, DIM2, DIM3,pmatrix3D); 

    return 0;
}

void display3DArray1(int rows, int cols1, int cols2,int (*arr)[][cols2]) {
    printf("\n");
    for(int i=0; i<rows; i++) {
        for(int j=0; j<cols1; j++) {
            for(int k=0; k<cols2; k++) {
                printf("*arr : %d adress: %p\n",*(*((*arr+i*cols1))+j*cols2+k),*((*arr+i*cols1))+j*cols2+k);
            }
        }
    }
}

void display3DArray2(int rows, int cols1, int cols2,int arr[][cols1][cols2]) {
    printf("\n");
    for(int i=0; i<rows; i++) {
        for(int j=0; j<cols1; j++) {
            for(int k=0; k<cols2; k++) {
                printf("*arr : %d adress: %p\n", *(*(*(arr+i)+j) + k), *(*(arr+i)+j) + k) ;
            }
        }
    }
}

代码有效,但有些东西我无法理解。当我尝试在第一个函数中使用第二个函数的第二个printf时,我得到一个编译错误:

  

&#34;无效使用带有未指定范围的数组&#34; - 在gcc下。

为什么*(arr + i)在第一个函数中不起作用?

5 个答案:

答案 0 :(得分:2)

您可以使用以下两种方式传递/打印矩阵:

void display3DArray1(int rows, int cols1, int cols2, int *A) {
    int *a, i, j, k;
    printf("\n");
    for(i=0; i<rows; i++) {
        for(j=0; j<cols1; j++) {
            for(k=0; k<cols2; k++) {
                a= A+(i*cols1*cols2)+(j*cols2)+k;
                printf("%d, %p\n", *a, a);
            }
        }
    }
}

void display3DArray2(int A[DIM1][DIM2][DIM3]) {
    int i, j, k;
    printf("\n");
    for(i=0; i<DIM1; i++) {
        for(j=0; j<DIM2; j++) {
            for(k=0; k<DIM3; k++) {
                printf("%d, %p\n", A[i][j][k], &A[i][j][k]);
            }
        }
    }
}

第一种方法不依赖于矩阵的维数;第二个。因此,第一个需要显式地址计算(行 i ,col j ,单元格 k )。

分别使用电话:

display3DArray1(DIM1, DIM2, DIM3, (int *)matrix3D);
display3DArray2(matrix3D);

注意矩阵的转换为int指针。

在您的代码中,您使用参数名称来指定矩阵的尺寸。在我的C版本中,这是不合法的;它们必须是常量。

答案 1 :(得分:2)

只是Paul Ogilvie回答的补充。

可变长度数组的正确用法是:

void display3DArray3(int rows, int cols1, int cols2,int arr[][cols1][cols2]) {
    printf("\n");
    for(int i=0; i<rows; i++) {
        for(int j=0; j<cols1; j++) {
            for(int k=0; k<cols2; k++) {
                printf("*arr : %d adress: %p\n", arr[i][j][k], &arr[i][j][k]);
            }
        }
    }
}

答案 2 :(得分:1)

说实话,我有点不解。核心问题是像f(T arr[])这样的函数参数声明声明了一个不完整的类型,其大小未知(无论是在编译时还是在运行时)。最初我认为函数参数声明中的空方括号只是声明一个指针 - 尽管符号 - 但是情况并非如此。该参数仍然具有数组类型,尽管不完整。 1

写作时

void display3DArray1(int rows, int cols1, int cols2,int (*arr)[][cols2])

你将指针声明为这种不完整类型的未知大小。这个指针不能以通常的方式操纵;特别是,为了跳转到下一个元素而添加它是不可能的,因为我们不知道当前元素的结束位置(因此下一个元素开始)。但你在

尝试
printf("*arr : %d adress: %p\n", *(*(*(arr+i)+j) + k), *(*(arr+i)+j) + k) ;

最里面的arr+1。只需解除引用即可,因为该变量可以保存第一个元素的地址。这就是第一个函数中的print:

 printf("*arr : %d adress: %p\n",*(*((*arr+i*cols1))+j*cols2+k),*((*arr+i*cols1))+j*cols2+k);

*arr。已知arr点的不完整数组的元素大小(这些元素是cols2整数的数组),以便我们可以添加到*arr,即使我们无法正确添加arr

为了完整性:为什么你可以在第二个函数中以这种方式访问​​arr?好吧:

void display3DArray2(int rows, int cols1, int cols2,int arr[][cols1][cols2])

arr声明为不完整的数组类型,为true;但其元素的大小是众所周知的:那些是cols1 x cols2 int矩阵。声明并没有说明有多少,但如果我们知道何时停止,我们肯定可以迭代它们。

<小时/> 1 当然这个阵列和其他任何一个阵列一样,衰变了#34;在大多数情况下指向一个指针,以便丢失的类型信息并不重要。但是,如果我们有指针,那就很重要。

答案 3 :(得分:0)

我很难找到用于解引用rank2和rank3矩阵的正确语法。目的是删除索引级别以加快执行速度。这是一些伪代码,可以帮助您入门。这更多是关于正确使用语法(MSVC 2019),而不是工作代码示例。

int recurse(int n, unsigned char rank2[13][4], unsigned char rank3[13][4][13])
{
    if (n < 13)
    {
       unsigned char (*deRefRank1)[4] = &rank2[n]; // deref matrix rank 2 to rank 1
       unsigned char(*deRefRank2)[4][13] = &rank3[n]; // deref matrix rank 3 to 2
       // insert pre-recurse code here ... use (*deRefRank1)[] and (*deRefRank2)[][]
       if (recurse(n + 1, rank2[n], rank3[n])
           return -1;
       // insert post-recurse code here ...
    }
    return 0;
}

答案 4 :(得分:-2)

“print”例程中的数组索引无效。 'matrix3D'的声明暗示该名称的类型是'指向int的指针'。注意:那里只有一个间接层。索引表达式在术语前面有一堆'' - s;在C中,这意味着''/ / em>'右边的项是一个指针,必须取消引用才能获得值'。这意味着你实际上将'matrix3D'视为'指向(指向int的指针)'的指针,这是太多的间接。