我有一个函数,我想把它作为一个参数,一个可变大小的二维数组。

到目前为止,我有这个:

void myFunction(double** myArray){
     myArray[x][y] = 5;
     etc...
}

我在代码的其他地方声明了一个数组:

double anArray[10][10];

然而,调用myFunction(anArray)会给我一个错误。

我不想在传入数组时复制它。在myFunction中所做的任何更改都应该改变anArray的状态。如果我理解正确,我只想传递一个指向2D数组的指针作为参数。该函数还需要接受不同大小的数组。比如[10][10][5][5]。我该怎么做呢?


当前回答

如果你想将int的[2][3]传递给void func(int** pp),你需要以下辅助步骤。

int a[2][3];
int* p[2] = {a[0],a[1]};
int** pp = p;

func(pp);

由于第一个[2]可以隐式指定,因此可以进一步简化为。

int a[][3];
int* p[] = {a[0],a[1]};
int** pp = p;

func(pp);

其他回答

我们可以使用几种方法将2D数组传递给函数:

Using single pointer we have to typecast the 2D array. #include<bits/stdc++.h> using namespace std; void func(int *arr, int m, int n) { for (int i=0; i<m; i++) { for (int j=0; j<n; j++) { cout<<*((arr+i*n) + j)<<" "; } cout<<endl; } } int main() { int m = 3, n = 3; int arr[m][n] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; func((int *)arr, m, n); return 0; } Using double pointer In this way, we also typecast the 2d array #include<bits/stdc++.h> using namespace std; void func(int **arr, int row, int col) { for (int i=0; i<row; i++) { for(int j=0 ; j<col; j++) { cout<<arr[i][j]<<" "; } printf("\n"); } } int main() { int row, colum; cin>>row>>colum; int** arr = new int*[row]; for(int i=0; i<row; i++) { arr[i] = new int[colum]; } for(int i=0; i<row; i++) { for(int j=0; j<colum; j++) { cin>>arr[i][j]; } } func(arr, row, colum); return 0; }

如果你想将int的[2][3]传递给void func(int** pp),你需要以下辅助步骤。

int a[2][3];
int* p[2] = {a[0],a[1]};
int** pp = p;

func(pp);

由于第一个[2]可以隐式指定,因此可以进一步简化为。

int a[][3];
int* p[] = {a[0],a[1]};
int** pp = p;

func(pp);

[10]不是指向指针的指针,它是一个连续的内存块,适合存储100个double类型的值,编译器知道如何寻址,因为你指定了维度。您需要将它作为数组传递给函数。你可以省略初始维度的大小,如下所示:

void f(double p[][10]) {
}

但是,这将不允许您传递除10之外的最后一个维度的数组。

c++中最好的解决方案是使用std::vector<std::vector<double> >:它几乎同样高效,而且明显更方便。

尽管表面上看,double**隐含的数据结构与固定c数组(double[][])的数据结构根本不兼容。 问题是这两种方法都是C(或c++)中处理数组的流行(尽管)被误导的方法。 参见https://www.fftw.org/fftw3_doc/Dynamic-Arrays-in-C_002dThe-Wrong-Way.html

如果你不能控制代码的任何一部分,你需要一个翻译层(这里称为adapt),解释在这里:https://c-faq.com/aryptr/dynmuldimary.html

您需要生成一个指针的辅助数组,指向c数组的每一行。

#include<algorithm>
#include<cassert>
#include<vector>

void myFunction(double** myArray) {
    myArray[2][3] = 5;
}

template<std::size_t N, std::size_t M>
auto adapt(double(&Carr2D)[N][M]) {
    std::array<double*, N> ret;
    std::transform(
        std::begin(Carr2D), std::end(Carr2D),
        ret.begin(),
        [](auto&& row) { return &row[0];}
    );
    return ret;
}

int main() {
    double anArray[10][10];

    myFunction( adapt(anArray).data() );

    assert(anArray[2][3] == 5);
}

(参见工作代码:https://godbolt.org/z/7M7KPzbWY)

如果它看起来像是一场灾难,那是因为,正如我所说,这两种数据结构从根本上是不兼容的。


如果可以控制代码的两端,那么现在最好使用现代(或半现代)数组库,比如Boost。MultiArray,提振。uBLAS,特征或多。 如果数组要小,你有“小”数组库,例如在Eigen内,或者如果你不能负担任何依赖,你可以尝试简单的std::array<std::array<double, N>, M>。

使用Multi,你可以简单地这样做:

#include<multi/array.hpp>

#include<cassert>

namespace multi = boost::multi;

template<class Array2D>
void myFunction(Array2D&& myArray) {
    myArray[2][3] = 5;
}

int main() {
    multi::array<double, 2> anArray({10, 10});

    myFunction(anArray);

    assert(anArray[2][3] == 5);
}

(工作代码:https://godbolt.org/z/7M7KPzbWY)

你可以像这样创建一个函数模板:

template<int R, int C>
void myFunction(double (&myArray)[R][C])
{
    myArray[x][y] = 5;
    etc...
}

然后你通过R和c有两个维度大小,每个数组大小都会创建一个不同的函数,所以如果你的函数很大,并且你用各种不同的数组大小调用它,这可能代价很高。你可以像这样使用它作为一个函数的包装器:

void myFunction(double * arr, int R, int C)
{
    arr[x * C + y] = 5;
    etc...
}

它将数组视为一维,并使用算术计算出索引的偏移量。在这种情况下,你可以这样定义模板:

template<int C, int R>
void myFunction(double (&myArray)[R][C])
{
    myFunction(*myArray, R, C);
}