【问题标题】:Pass By Reference Multidimensional Array With Unknown Size传递未知大小的引用多维数组
【发布时间】:2013-03-06 10:51:44
【问题描述】:

如何在 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 中,您需要将大小指定为附加参数或第一个元素(如果您使用的是整数类型) .
  • 其实你可以通过引用传递一个未知大小的数组! (好吧,结构有一个技巧,但我们不要去那里)。你试过什么?
  • 在 C 中这是不可能的,因为 C 没有引用。在 C++ 中,这是不可能的,因为它不支持变长数组。
  • 在 C 中,简而言之,你不需要。您必须有一个 some 类型的构造,该构造在使用时指定大小。如何收集尺寸信息取决于您。

标签: c++ c


【解决方案1】:

简单地说,你不能。在 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);?
  • 我建议在 C++ 中使用boost::array
  • 我尝试使用这个void foo(int n, int k, int (*arr)[n][k])并得到error: use of parameter 'n' outside function body
  • @IfanIqbal 我编译并运行这段代码。你是用-std=c99 编译的吗? (此外,在代码中发现一个错误不应让您立即不接受我的回答。)
【解决方案2】:

H2CO3 的解决方案适用于支持 VLA 的 C99 或 C2011 编译器。对于支持 VLA 的 C89 或 C2011 编译器,或者(上帝保佑)K&R C 编译器,您必须做其他事情。

假设您要传递一个连续分配的数组,您可以传递一个指向 第一个元素 (&amp;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] );
  }
}

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

【讨论】:

    【解决方案3】:

    这是对@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,您调用foo 也就是数组int ap[M][N];

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

    因为您保证所有行都被连续分配给彼此。 这种分配效率更高。

    【讨论】:

      【解决方案4】:

      John Bode 的解释很好,但是有一个小错误: 应该是

      i * cols + j
      

      而不是

      i * rows + j
      

      【讨论】:

        【解决方案5】:

        如果你真的想要引用,那么它只能在 C++ 中。

        通过引用传递的二维 int 数组示例

        void function_taking_an_array(int**& multi_dim_array);
        

        但是引用没有任何优势,所以简单地使用:

        void function_taking_an_array(int** multi_dim_array);
        

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

        【讨论】:

        • 嗯,不。 int ** 是指向 int 的指针,它不是二维数组。
        • 可以表示一个二维数组。使用预定义的数组大小或信号量值(或指定维度作为附加参数)。最好的例子是 main 函数,char** argv 函数代表一个 char 数组。
        • 它当然可以模拟它们,如果你使用malloc()并传递大小等等。但是(双)指针仍然不是(二维)数组。
        猜你喜欢
        • 2010-10-06
        • 1970-01-01
        • 2019-04-27
        • 2012-04-27
        • 2014-04-13
        • 2021-10-31
        • 1970-01-01
        • 2015-03-18
        相关资源
        最近更新 更多