将多维数组的指针传递给函数,指定边界

Pass pointer of an array of multi-dimensional arrays to a function, specifying bounds

假设我有多个(可变数量)二维数组(甚至可能是可变长度的):

int a[2][2] = {{1,2},{3,4}};
int b[2][2] = {{5,6},{7,8}};
...

我现在想将其传递给一个函数。我 不想 将 2D 数组复制到 3D 数组中。但是,我想指定边界,以便函数知道二维数组的维度,以便我可以使用 [i][j]

方便地对它们进行索引

我如何格式化函数的签名,以便它接受指向一个数组(未知长度)的指针,该数组包含二维数组, 现在的维度是什么?

例如像

void myfunc(int[][3] *test, int len)

当然这在语法上是无效的。在 C 中不可能在数组 inside 中指定数组(通过指针传递)的边界吗?我会被迫将 ab 移动到指针中,还是被迫将它们复制到 3D 数组中?

如果您的编译器支持可变长度数组,您可以编写

void myfunc( int rows, int cols, int a[rows][cols] );

考虑到第三个参数被隐式转换为类型 int ( * )[cols],即在您处理指向一维数组的指针的函数中。不过你可以使用像

这样的表达式
for ( int i = 0; i < rows; i++ )
{
    for ( int j = 0; j < cols; j++ ) a[i][j] = value;
}

否则如果编译器不支持变长数组并且所有数组的第二维都相同那么函数可以这样声明

void myfunc( int ( *a )[2], int rows );

考虑到这个声明

int[][3] *test

无论如何都是不正确的。

如果你想传递几个二维数组,那么你可以在main中声明一个一维数组,比如

int a[2][2] = {{1,2},{3,4}};
int b[2][2] = {{5,6},{7,8}};
//...

int ( *p[] )[2] = { a, b, /*...*/ };

然后将其传递给一个函数。

在这种情况下,函数看起来像

void myfunc( int ( **p )[2], size_t n );

这是一个演示程序

#include <stdio.h>

void myfunc( int ( **p )[2], size_t n )
{
    for ( size_t i = 0; i < n; i++ )
    {
        for ( size_t j = 0; j < 2; j++ )
        {
            for ( size_t k = 0; k < 2; k++ ) printf( "%d ", p[i][j][k] );
            putchar( '\n' );
        }
        putchar( '\n' );
    }
}

int main(void) 
{
    int a[2][2] = {{1,2},{3,4}};
    int b[2][2] = {{5,6},{7,8}};

    int ( *p[] )[2] = { a, b };

    myfunc( p, sizeof( p ) / sizeof( *p ) );

    return 0;
}

它的输出是

1 2 
3 4 

5 6 
7 8 

如果数组的第一维不固定且不断变化,那么您也可以将数组的第一维数组传递给函数

如果你有两个 东西你需要传递给一个函数,你要么

  1. 传递两个单独的参数;或
  2. 创建某种包含(指向)所述事物的数据结构,并传递(指向)它。

你的东西是数组还是其他什么都没关系。

当您拥有可变数量的 事物 时,同样的事情也成立。您可以将可变数量的参数传递给函数,但这是一个单独的主题,所以让我们集中讨论选项 2。在这种情况下,您的数据结构应该是指向 things 的指针数组。

好的,当你的 thing 有一个复杂的类型时,你如何创建一个,比如一个数组(指向函数的指针数组 return 一个指向阵列,或其他)?答案很简单:使用 typedef。

typedef int MyThing[2][2]; // could be anything
MyThing one = {{1,2},{3,4}};
MyThing two = ...; // etc

MyThing* manyPointersToThings[] = {&one, &two};

void myFunc(int nThings, MyThing things[nThings]) {

   // in here, each things[i] is a *pointer* to MyThing
   (*things[0])[1][2] = 42;
    // whatever
}

这适用于任何类型的事物。如果你的 thing 实际上是一个数组,还有另一种选择:你的数据结构可以存储指向数组第一个元素的指针,而不是指向数组本身的指针。

typedef int MyThing[2]; // this type names an *element* of your array
MyThing one[2] = {{1,2},{3,4}};
MyThing two[2] = ...; // etc

MyThing* manyPointersToThings[] = {one, two}; // note no & here

void myFunc(int nThings, MyThing things[nThings]) {

   // in here, each things[i] is a pointer to the first element of an array
   things[0][1][2] = 42;
    // whatever
}

使用此选项,您可以获得一些灵活性,因为您的数组不需要都具有相同的大小。您还会在括号中丢失丑陋的取消引用。

为了完整起见,以下是没有 typedef 的相同函数的原型:

void myFunc(int nThings, int (*things[nThings])[2][2]) // version 1
void myFunc(int nThings, int (*things[nThings])[2]) // version 2

这些比 typedef 版本更灵活一些,因为现在您可以使用变量(另一个参数)而不是硬编码的数字 2。

如果你写上面的东西有困难,试试this