C 将多维可变长度数组传递给函数

C 将多维可变长度数组传递给函数,c,arrays,c99,C,Arrays,C99,有很多类似的问题,但我仍然找不到任何与C99/C11中可变长度数组特性相关的答案 如何将多维可变长度数组传递给C99/C11中的函数 例如: void foo(int n, int arr[][]) // <-- error here, how to fix? { } void bar(int n) { int arr[n][n]; foo(n, arr); } 我知道,将数组传递给这样的函数不是最佳实践,我一点也不喜欢。使用平面指针或对象(如std:vector)或其

有很多类似的问题,但我仍然找不到任何与C99/C11中可变长度数组特性相关的答案

如何将多维可变长度数组传递给C99/C11中的函数

例如:

void foo(int n, int arr[][]) // <-- error here, how to fix?
{
}

void bar(int n)
{
    int arr[n][n];
    foo(n, arr);
}

我知道,将数组传递给这样的函数不是最佳实践,我一点也不喜欢。使用平面指针或对象(如std:vector)或其他方式可能更好。但是,从理论上讲,我有点好奇,这里的答案是:

在C和C++中传递数组到函数有点可笑。没有数组类型的右值,因此实际上是在传递指针

要寻址2D数组(真实数组,而不是数组数组),需要传递2个数据块:

  • 指向其开始位置的指针
  • 一排有多宽

这是两个独立的值,无论是C还是C++,还是VLA或无或不。 写这篇文章的一些方法: 最简单的,可以在任何地方工作,但需要更多的手工工作

void foo(int width, int* arr) {
    arr[x + y*width] = 5;
}
VLA,标准C99

void foo(int width, int arr[][width]) {
    arr[x][y] = 5;
}
带反向参数的VLA,正向参数声明(GNU C扩展)

C++ +W/VLA(GNU C++扩展,极其丑陋)

void foo(int-width,int*ptr){
typedef int arrtype[][宽度];
arrtype&arr=*重新解释铸件(ptr);
arr[x][y]=5;
}
重要的评论: 二维数组的[x][y]表示法有效,因为数组的类型包含宽度。编译时不能固定VLA=数组类型

因此:如果你不能使用VLA,那么

  • 用C语言是无法处理的
  • 没有C++中的代理类W/过载操作符重载,就无法处理它。

如果你可以使用VLA(C99或GNU C++扩展),那么……

  • 你在C区是绿色的
  • 您仍然需要C++中的混乱,而不是使用类。
< C++ >代码> Boo::多数组> <代码>是一个可靠的选择。 变通办法 对于二维阵列,可以进行两个单独的分配:

  • 指向
    T
    (a)的一维指针数组
  • T
    (B)的二维数组
然后将(A)中的指针设置为指向(B)中相应的行

使用此设置,您只需将(A)作为一个简单的
T**
传递,它将在
[x][y]
索引中运行良好

这个解决方案很适合2D,但需要越来越多的样板文件来实现更高的维度。由于额外的间接层,它也比VLA解决方案慢


您还可能遇到类似的解决方案,每个
B
行都有单独的分配。在C中,这看起来像一个malloc-In-a-loop,类似于C++的向量向量。但是,这会使整个数组中的一个块的好处消失。

在函数中传递数组到C和C++中有点可笑。没有数组类型的右值,因此实际上是在传递指针

要寻址2D数组(真实数组,而不是数组数组),需要传递2个数据块:

  • 指向其开始位置的指针
  • 一排有多宽

这是两个独立的值,无论是C还是C++,还是VLA或无或不。 写这篇文章的一些方法: 最简单的,可以在任何地方工作,但需要更多的手工工作

void foo(int width, int* arr) {
    arr[x + y*width] = 5;
}
VLA,标准C99

void foo(int width, int arr[][width]) {
    arr[x][y] = 5;
}
带反向参数的VLA,正向参数声明(GNU C扩展)

C++ +W/VLA(GNU C++扩展,极其丑陋)

void foo(int-width,int*ptr){
typedef int arrtype[][宽度];
arrtype&arr=*重新解释铸件(ptr);
arr[x][y]=5;
}
重要的评论: 二维数组的[x][y]表示法有效,因为数组的类型包含宽度。编译时不能固定VLA=数组类型

因此:如果你不能使用VLA,那么

  • 用C语言是无法处理的
  • 没有C++中的代理类W/过载操作符重载,就无法处理它。

如果你可以使用VLA(C99或GNU C++扩展),那么……

  • 你在C区是绿色的
  • 您仍然需要C++中的混乱,而不是使用类。
< C++ >代码> Boo::多数组> <代码>是一个可靠的选择。 变通办法 对于二维阵列,可以进行两个单独的分配:

  • 指向
    T
    (a)的一维指针数组
  • T
    (B)的二维数组
然后将(A)中的指针设置为指向(B)中相应的行

使用此设置,您只需将(A)作为一个简单的
T**
传递,它将在
[x][y]
索引中运行良好

这个解决方案很适合2D,但需要越来越多的样板文件来实现更高的维度。由于额外的间接层,它也比VLA解决方案慢


您还可能遇到类似的解决方案,每个
B
行都有单独的分配。在C中,这看起来像一个malloc-In-a-loop,类似于C++的向量向量。但是,这样做会失去将整个数组放在一个块中的好处。

没有明确的方法可以做到这一点,但您可以使用一种变通方法将二维数组视为一维数组,然后在函数内部将其重新转换为二维数组

void foo2(int n, int *arr) 
{
    int *ptr; // use this as a marker to go to next block
    int i;
    int j;

    for(i = 0; i < n; i++)
    {
        ptr = arr + i*n; // this is the starting for arr[i] ...
        for (j = 0; j < n ;j++)
        {
            printf(" %d ", ptr[j]); // This is same as arr[i][j]
        }
    }
}

void bar2()
{
    int arr[10][10];
    foo2(10, (int *)arr);
}
void foo2(int n,int*arr)
{
int*ptr;//将其用作转到下一个块的标记
int i;
int j;
对于(i=0;i
执行此操作没有明确的方法,但您可以使用变通方法将二维数组视为一维数组,然后在函数内部将其重新转换为二维数组

void foo2(int n, int *arr) 
{
    int *ptr; // use this as a marker to go to next block
    int i;
    int j;

    for(i = 0; i < n; i++)
    {
        ptr = arr + i*n; // this is the starting for arr[i] ...
        for (j = 0; j < n ;j++)
        {
            printf(" %d ", ptr[j]); // This is same as arr[i][j]
        }
    }
}

void bar2()
{
    int arr[10][10];
    foo2(10, (int *)arr);
}
void foo2(int n,int*arr)
{
int*ptr;//将其用作转到下一个块的标记