将多维可变长度数组传递给函数 [英] Passing a multidimensional variable length array to a function

查看:26
本文介绍了将多维可变长度数组传递给函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

There are tons of similar questions, but still I could not find any answer relevant for the feature of variable length arrays in C99/C11.

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

How to pass multidimensional variable length array to a function in C99/C11?

例如:

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

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

编译器 (g++-4.7 -std=gnu++11) 说:
错误:将arr"声明为多维数组必须对除第一个维度外的所有维度都具有边界

如果我把它改成int *arr[],编译器仍然报错:
错误:无法将参数 '2' 的 'int (*)[(((sizetype)(((ssizetype)n) + -1)) + 1)]' 转换为 'int**' 到 'void foo(int, int**)'

If I change it to int *arr[], compiler still complains:
error: cannot convert ‘int (*)[(((sizetype)(((ssizetype)n) + -1)) + 1)]’ to ‘int**’ for argument ‘2’ to ‘void foo(int, int**)’

下一个问题,如何按值传递,如何按引用传递?显然,通常您不希望在将整个数组传递给函数时复制整个数组.

Next question, how to pass it by value and how to pass it by reference? Apparently, usually you don't want the entire array to be copied when you pass it to a function.

使用常量长度数组很简单,因为正如常量"所暗示的那样,您应该在声明函数时知道长度:

With constant length arrays it's simple, since, as the "constant" implies, you should know the length when you declare the function:

void foo2(int n, int arr[][10]) // <-- ok
{
}

void bar2()
{
    int arr[10][10];
    foo2(10, arr);
}

我知道,像这样将数组传递给函数不是最佳实践,我根本不喜欢它.使用平面指针或对象(如 std:vector)或其他方式可能更好.但是,从理论的角度来看,我仍然有点好奇这里的答案是什么.

I know, passing arrays to functions like this is not a best practice, and I don't like it at all. It is probably better to do with flat pointers, or objects (like std:vector) or somehow else. But still, I'm a bit curios what is the answer here from a theoretical standpoint.

推荐答案

在 C 和 C++ 中将数组传递给函数有点有趣.没有数组类型的右值,所以你实际上是在传递一个指针.

Passing arrays to functions is a bit funny in C and C++. There are no rvalues of array types, so you're actually passing a pointer.

要寻址一个二维数组(一个真正的数组,而不是数组数组),您需要传递 2 个数据块:

To address a 2D array (a real one, not array of arrays), you'll need to pass 2 chunks of data:

  • 指向它开始位置的指针
  • 一行有多宽

这是两个独立的值,无论是 C 或 C++ 还是带有 VLA 或不带或诸如此类.

And these are two separate values, be it C or C++ or with VLA or without or whatnot.

最简单,适用于任何地方,但需要更多的手动工作

Simplest, works everywhere but needs more manual work

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 扩展)

VLA w/ reversed arguments, forward parameter declaration (GNU C extension)

void foo(int width; int arr[][width], int width) {
    arr[x][y]=5;
}

带有 VLA 的 C++(GNU C++ 扩展,非常丑陋)

C++ w/ VLA (GNU C++ extension, terribly ugly)

void foo(int width, int* ptr) {
    typedef int arrtype[][width];
    arrtype& arr = *reinterpret_cast<arrtype*>(ptr);
    arr[x][y]=5;
}

重要评论:

二维数组的 [x][y] 表示法有效,因为数组的类型包含宽度.没有 VLA = 数组类型必须在编译时固定.

Big remark:

The [x][y] notation with a 2D array works because the array's type contains the width. No VLA = array types must be fixed at compile-time.

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

Hence: If you can't use VLA, then...

  • 没有办法在 C 中处理它,
  • 如果没有代理类和 C++ 中的重载运算符重载,就无法处理它.

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

If you can use VLA (C99 or GNU C++ extensions), then...

  • 你在 C 语言中处于绿色状态,
  • 您仍然需要使用 C++,请改用类.

对于 C++,boost::multi_array 是一个不错的选择.

For C++, boost::multi_array is a solid choice.

对于二维数组,您可以进行两次单独的分配:

For 2D arrays, you can make two separate allocations:

  • 指向T (A) 的一维指针数组
  • T (B)
  • 的二维数组
  • a 1D array of pointers to T (A)
  • a 2D array of T (B)

然后将 (A) 中的指针设置为指向 (B) 的相应行.

Then set the pointers in (A) to point into respective rows of (B).

通过此设置,您可以将 (A) 作为简单的 T** 传递,并且它在 [x][y] 索引中表现良好.

With this setup, you can just pass (A) around as a simple T** and it will behave well with [x][y] indexing.

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

This solution is nice for 2D, but needs more and more boilerplate for higher dimensions. It's also slower than the VLA solution because of the extra layer of indirection.

您也可能遇到类似的解决方案,为每个 B 的行单独分配.在 C 中,这看起来像是 malloc-in-a-loop,类似于 C++ 的 vector-of-vectors.然而,这剥夺了将整个数组放在一个块中的好处.

You may also run into a similar solution with a separate allocation for every B's row. In C this looks like a malloc-in-a-loop, and is analogous of C++'s vector-of-vectors. However this takes away the benefit of having the whole array in one block.

这篇关于将多维可变长度数组传递给函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆