通过引用传递未知大小的多维数组

3
如何在C或C++中传递未知大小的多维数组的引用?

编辑:

例如,在主函数中有以下内容:
int main(){
    int x, y;
    int arr[x][y];
    // pass_by_ref(/* passing just arr[][] by reference */);
}  

并且这个功能是:

void pass_by_ref(/* proper parameter for arr[][] */){
    // int size_x_Arr = ???
    // int size_y_arr = ???
}

如何实现注释掉的这行代码?

在C++中,您可以使用std::vector&或其他类似类型,而在C中,您需要将大小指定为附加参数或作为第一个元素(如果您正在使用整数类型)。 - Zeta
实际上,你只能通过未知大小的引用传递数组!(好吧,有一个结构体的技巧,但我们不去那里)。你尝试过什么? - cdarke
在C语言中不可能,因为C语言没有引用。在C++中也不可能,因为它不支持可变长度数组。 - user529758
可能是重复的问题:如何将多维数组传递给函数? - Bo Persson
在C语言中,简而言之,你不能。你必须有某种构造,在使用时指定大小。如何获取大小信息取决于你。 - WhozCraig
你如何准确地定义“未知大小的多维数组”? - qPCR4vir
5个回答

4
简单来说,你不能这样做。在 C 语言中,你无法通过引用传递参数,因为 C 没有引用。在 C++ 中,你无法传递未知大小的数组,因为 C++ 不支持可变长度数组。
替代方案:在 C99 中,传递指向可变长度数组的指针;在 C++ 中,传递对 std::vector<std::vector<T>> 的引用。
以下是 C99 的演示:
#include <stdio.h>

void foo(int n, int k, int (*arr)[n][k])
{
    int i, j;
    for (i = 0; i < n; i++) {
        for (j = 0; j < k; j++) {
            printf("%3d ", (*arr)[i][j]);
        }
        printf("\n");
    }
}

int main(int argc, char *argv[])
{
    int a = strtol(argv[1], NULL, 10);
    int b = strtol(argv[2], NULL, 10);

    int arr[a][b];
    int i, j;
    for (i = 0; i < a; i++) {
        for (j = 0; j < b; j++) {
            arr[i][j] = i * j;
        }
    }

    foo(a, b, &arr);

    return 0;
}

C++03演示:

#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>

void foo(std::vector < std::vector < int > > &vec)
{
    for (std::vector < std::vector < int > >::iterator i = vec.begin(); i != vec.end(); i++) {
        for (std::vector<int>::iterator j = i->begin(); j != i->end(); j++) {
            std::cout << *j << " ";
        }
        std::cout << std::endl;
    }
}

int main(int argc, char *argv[])
{
    int i = strtol(argv[1], NULL, 10);
    int j = strtol(argv[2], NULL, 10);

    srand(time(NULL));

    std::vector < std::vector < int > > vec;
    vec.resize(i);
    for (std::vector < std::vector < int > >::iterator it = vec.begin(); it != vec.end(); it++) {
        it->resize(j);
        for (std::vector<int>::iterator jt = it->begin(); jt != it->end(); jt++) {
            *jt = random() % 10;
        }
    }

    foo(vec);

    return 0;
}

这行代码的含义是什么:strtol(argv[1], NULL, 10); - Ifan Iqbal
我建议在C++中使用boost::array - AxelOmega
我尝试使用 void foo(int n, int k, int (*arr)[n][k]),但是出现了 error: use of parameter 'n' outside function body 错误。 - Ifan Iqbal
@IfanIqbal 我编译并运行了这段代码。你是否使用了-std=c99进行编译?(另外,发现一处错误不应该立即取消接受我的答案。) - user529758

3

H2CO3的溶液适用于支持可变长度数组(VLAs)的C99或C2011编译器。对于不支持VLAs的C89或C2011编译器(更不用说K&R C编译器了),您需要采取其他措施。

假设您正在传递一个连续分配的数组,您可以传递指向第一个元素(&a[0][0])的指针以及维数大小,然后将其视为一维数组,将索引映射如下:

void foo( int *a, size_t rows, size_t cols )
{
  size_t i, j;

  for (i = 0; i < rows; i++)
  {
    for (j = 0; j < cols; j++)
    {
      a[i * rows + j] = some_value();
    }
  }
}

int main( void )
{
  int arr[10][20];

  foo( &arr[0][0], 10, 20 );
  ...
  return 0;
}

这将适用于在堆栈上分配的数组:
T a[M][N];

对于形式为动态分配数组的情况:

T (*ap)[N] = malloc( M * sizeof *ap );

由于两者都具有连续分配的行,因此这将会起作用。对于以下形式的动态分配数组,这将无法工作(或者至少不能保证会工作):

T **ap = malloc( M * sizeof *ap );
if (ap)
{
  size_t i;
  for (i = 0; i < M; i++)
  {
    ap[i] = malloc( N * sizeof *ap[i] );
  }
}

因为不能保证所有行都被连续地分配给彼此。


0
约翰·博德的解释非常好,但有一个小错误:应该是

i * cols + j

替代

i * rows + j

0

这是对@John Bode的好答案进行评论的一种方式

对于以下形式的动态分配数组,这将无法工作(或者至少不能保证工作):

但是这个变体会:

T **ap = malloc( M * sizeof *ap );
if (ap) return NULL;     ---> some error atention
if (ap)
{
  ap[0] = malloc( M * N * sizeof *ap[i] );
  if (ap[0]) { free(ap); return NULL;}     ---> some error atention
  size_t i;
  for (i = 1; i < M; i++)
  {
    ap[i] = ap[0] + i * N;
  }
}

使用后:

free(ap[0]);
free(ap);

Tint时,您可以像对待数组int ap[M][N];一样调用foo

  foo( &ap[0][0], M, N);

由于您保证了所有行都是连续分配的,因此这种分配方式更加高效。


-1
如果你真的需要引用,那么只有在C++中才有。

一个二维int数组通过引用传递的例子。

void function_taking_an_array(int**& multi_dim_array);

但是引用并没有任何优势,所以只需使用:

void function_taking_an_array(int** multi_dim_array);

我建议您使用容器来保存您的数组。

不,int **是指向int类型的指针的指针,而不是二维数组。 - user529758
可以使用预定义的数组大小或信号量值(或将维度指定为附加参数)来表示二维数组。最好的例子是main函数,其中char ** argv函数表示一个字符数组的数组。 - Geoffroy
如果您使用malloc()并传入尺寸,它确实可以模拟它们以及其他内容。但是,(双)指针仍然不是(二维)数组。 - user529758

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接