繁体   English   中英

传递未知大小的数组来运行

[英]Passing array with unknown size to function

假设我有一个名为MyFunction(int myArray[][])的函数,它执行一些数组操作。

如果我像这样编写参数列表,编译器会抱怨它需要在编译时知道数组的大小。 有没有办法重写参数列表,以便我可以传递任何大小的数组到函数?

我的数组的大小由类中的两个static const int定义,但编译器不会接受类似MyFunction(int myArray[Board::ROWS][Board::COLS])

如果我可以将数组转换为向量然后将向量传递给MyFunction怎么办? 是否有可以使用的单行转换或我必须手动进行转换?

在C ++语言中,多维数组声明必须始终包含除第一个之外的所有大小。 所以,你想做的事情是不可能的。 如果不显式指定大小,则无法声明内置多维数组类型的参数。

如果需要将运行时大小的多维数组传递给函数,则可以忘记使用内置的多维数组类型。 这里的一个可能的解决方法是使用“模拟的”多维数组(指向其他1D数组的指针的1D数组;或通过索引重新计算来模拟多维数组的普通1D数组)。

在C ++中,使用std :: vector来建模数组,除非您有使用数组的特定原因。

填充0的3x2向量的示例被称为“myArray”被初始化:

vector< vector<int> > myArray(3, vector<int>(2,0));

传递这个结构是微不足道的,你不需要通过传递长度(因为它保持跟踪):

void myFunction(vector< vector<int> > &myArray) {
    for(size_t x = 0;x < myArray.length();++x){
        for(size_t y = 0;y < myArray[x].length();++y){
            cout << myArray[x][y] << " ";
        }
        cout << endl;
    }
}

或者,您可以使用迭代器迭代它:

void myFunction(vector< vector<int> > &myArray) {
    for(vector< vector<int> >::iterator x = myArray.begin();x != myArray.end();++x){
        for(vector<int>::iterator y = x->begin();y != x->end();++y){
            cout << *y << " ";
        }
        cout << endl;
    }
}

在C ++ 0x中,您可以使用auto关键字来清理向量迭代器解决方案:

void myFunction(vector< vector<int> > &myArray) {
    for(auto x = myArray.begin();x != myArray.end();++x){
        for(auto y = x->begin();y != x->end();++y){
            cout << *y << " ";
        }
        cout << endl;
    }
}

在c ++ 0x中,for_each对lambdas变得可行

void myFunction(vector< vector<int> > &myArray) {
    for_each(myArray.begin(), myArray.end(), [](const vector<int> &x){
        for_each(x->begin(), x->end(), [](int value){
            cout << value << " ";
        });
        cout << endl;
    });
}

或者基于c ++ 0x循环的范围:

void myFunction(vector< vector<int> > &myArray) {
    for(auto x : myArray){
        for(auto y : *x){
            cout << *y << " ";
        }
        cout << endl;
    }
}

*我现在不接近编译器并且没有测试过这些,请随时更正我的示例。


如果您在编译时知道数组的大小,则可以执行以下操作(假设大小为[x] [10]):

MyFunction(int myArray[][10])

如果你需要传入一个可变长度数组(动态分配或可能只是一个需要采用不同大小的数组的函数),那么你需要处理指针

正如对这个答案的评论所述:

boost :: multiarray可能是合适的,因为它可以更有效地建模多维数组。 向量向量可能会对关键路径代码产生性能影响,但在典型情况下,您可能不会注意到问题。

将其作为指针传递,并将维度作为参数。

void foo(int *array, int width, int height) {
    // initialize xPos and yPos
    assert(xPos >= 0 && xPos < width);
    assert(yPos >= 0 && yPos < height);
    int value = array[yPos * width + xPos];
}

这假设您有一个简单的二维数组,如int x[50][50]

已经有一组答案与大多数常见的建议:使用std::vector ,实现matrix类,在函数参数中提供数组的大小...我只想添加另一个基于的解决方案本机数组 - 如果可能,请注意您应该使用更高级别的抽象。

好歹:

template <std::size_t rows, std::size_t cols>
void function( int (&array)[rows][cols] )
{
   // ...
}

此解决方案使用对数组的引用 (注意&array周围的括号),而不是使用pass-by-value语法。 这会强制编译器不将数组衰减为指针。 然后两个大小(可以作为编译时常量提供)可以定义为模板参数,编译器将为您减去大小。

注意:您在问题中提到尺寸实际上是静态常量, 如果您在类声明中提供值,则应该能够在函数签名中使用它们:

struct test {
   static const int rows = 25;
   static const int cols = 80;
};
void function( int *array[80], int rows ) {
   // ...
}

请注意,在签名中,我更喜欢更改指向数组的指针的双维数组。 原因是是编译器解释的方式,这种方式很明显,不能保证函数的调用者将传递一个恰好25行的数组(编译器不会强制执行它),它是因此显然需要第二个整数参数,其中调用者传递行数。

你不能传递这样的任意大小; 编译器不知道如何生成指针算法。 你可以这样做:

MyFunction(int myArray[][N])

或者你可以这样做:

MyFunction(int *p, int M, int N)

但是当你调用它时你必须取第一个元素的地址(即MyFunction(&arr[0][0], M, N)

您可以使用容器类在C ++中解决所有这些问题; std::vector将是一个很好的起点。

编译器抱怨,因为它需要知道除了第一个维度之外的所有维度的大小才能解决数组中的元素。 例如,在以下代码中:

int array[M][N];
// ...
array[i][j] = 0;

为了解决该元素,编译器生成如下内容:

*(array+(i*N+j)) = 0;

因此,您需要重写这样的签名:

MyFunction(int array[][N])

在这种情况下,您将使用固定维度,或使用更通用的解决方案,例如(自定义)动态2D数组类或vector<vector<int> >

是的: MyFunction(int **myArray);

但是要小心。 你最好知道你在做什么。 这只接受一个int指针数组。

由于您尝试传递数组数组,因此您需要一个常量表达式作为其中一个维度:

MyFunction(int myArray[][COLS]);

你需要在编译时使用COLS

我建议使用矢量代替。

  1. 使用vector<vector<int> > (如果不保证底层存储是连续的,这将是作弊)。

  2. 使用指向element-of-arrayint* )和sizeM*N )参数的指针。 这里是龙。

首先,让我们看看为什么编译器抱怨。

如果数组定义为int arr[ ROWS ][ COLS ]; 那么任何数组符号arr[ i ][ j ]都可以转换为指针符号

*( arr + i * COLS + j )

观察表达式只需要COLS ,它不需要ROWS 因此,数组定义可以等效地编写为

int arr [][ COLS ];

但是, 错过第二个维度是不可接受的 有关详细信息,请阅读此处

现在,关于你的问题:

有没有办法重写参数列表,以便我可以传递任何大小的数组到函数?

是的,也许你可以使用指针,例如MyFunction( int * arr ); 但是,考虑一下, MyFunction()如何知道停止访问数组的位置? 要解决这个问题,你需要另一个参数作为数组的长度,例如MyFunction( int * arr, size_t arrSize );

传递指针并自己进行索引或改为使用Matrix类。

使用MyFunction(int *myArray[])
如果使用MyFunction(int **myArray)传递一个int someArray[X][Y] ,程序将崩溃。
编辑:不要使用第一行,它在评论中解释。

是的 - 只需将其作为指针传递:

MyFunction(int** someArray)

缺点是您可能还需要传递数组的长度

我不知道C ++,但C99标准引入了可变长度数组。

所以这适用于支持C99的编译器:

void func(int rows, int cols, double[rows][cols] matrix) {
    for (int r = 0; r < rows; r++) {
        for (int c = 0; c < cols; c++) {
            printf("%f", matrix[r][c]);
        }
    }
}

请注意,size参数位于数组之前。 实际上,在编译时只需知道列数,因此这也是有效的:

void func(int rows, int cols, double[][cols] matrix)

对于三个或更多维度,除第一维之外的所有维度必须具有已知的大小。 ArunSaha联系的答案解释了原因。

老实说,我不知道C ++是否支持可变长度数组,所以这可能有效,也可能无效。 在任何一种情况下,您也可以考虑将数组封装在某种矩阵类中。

编辑:从您的编辑,看起来C ++可能不支持此功能。 矩阵类可能是要走的路。 (或者std :: vector,如果你不介意内存可能不会连续分配。)

不传递数组,这是一个实现细节。 通过董事会

MyFunction(Board theBoard)
{
    ...
}

在C ++ 0x中, 您可以使用std::initializer_list<...>来完成此任务:

MyFunction(std::initializer_list<std::initializer_list<int>> myArray);

并使用它(我推测)像这样( 基于语法范围 ):

for (const std::initializer_list<int> &subArray: myArray)
{
    for (int value: subArray)
    {
        // fun with value!
    }
}

实际上我的数组的大小是由类中的两个static const int定义的,但是编译器不会接受像MyFunction(int myArray[Board::ROWS][Board::COLS])这样的东西MyFunction(int myArray[Board::ROWS][Board::COLS])

这很奇怪,它对我来说非常好:

struct Board
{
    static const int ROWS = 6;
    static const int COLS = 7;
};

void MyFunction(int myArray[Board::ROWS][Board::COLS])
{
}

也许ROWS和COLS是私人的吗? 你能告诉我们一些代码吗?

在C ++中,使用内置数组类型是即时失败的。 您可以使用boost :: / std ::数组数组或数组向量。 原始数组不能达到任何实际用途

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM