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

时间:2010-10-21 19:15:16

标签: c++ arrays

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

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

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

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

17 个答案:

答案 0 :(得分:14)

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

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

答案 1 :(得分:12)

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

一个3x2向量的示例,其中填充了名为“myArray”的0被初始化:

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])

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

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

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

答案 2 :(得分:5)

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

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]

答案 3 :(得分:3)

已经有一组答案包含大多数常见建议:使用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 ) {
   // ...
}

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

答案 4 :(得分:2)

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

MyFunction(int myArray[][N])

或者你可以这样做:

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

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

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

答案 5 :(得分:2)

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

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

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

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

因此,您需要重新编写您的签名:

MyFunction(int array[][N])

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

答案 6 :(得分:1)

是:MyFunction(int **myArray);

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

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

MyFunction(int myArray[][COLS]);

您需要在编译时拥有COLS

我建议改为使用vector

答案 7 :(得分:1)

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

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

答案 8 :(得分:1)

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

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

*( arr + i * COLS + j )

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

int arr [][ COLS ];

但是,缺少第二个维度是不可接受的。有关详细信息,请阅读here

现在,关于你的问题:

  

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

是的,也许您可​​以使用指针,例如MyFunction( int * arr );。但是,想想看,MyFunction()如何知道停止访问数组的位置?要解决这个问题,你需要另一个参数来表示数组的长度,例如: MyFunction( int * arr, size_t arrSize );

答案 9 :(得分:0)

  

实际上我的数组的大小是由类中的两个static const int定义的,但编译器不会接受类似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是私有的?你能告诉我们一些代码吗?

答案 10 :(得分:0)

在C ++ 0x中,you can use std::initializer_list<...>完成此任务:

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

并像这样使用它(我推测)(使用range based for syntax):

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

答案 11 :(得分:0)

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

MyFunction(Board theBoard)
{
    ...
}

答案 12 :(得分:0)

我不了解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。)

答案 13 :(得分:0)

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

MyFunction(int** someArray)

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

答案 14 :(得分:0)

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

答案 15 :(得分:0)

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

答案 16 :(得分:-1)

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