【问题标题】:variable-size type declared outside of any function在任何函数之外声明的可变大小类型
【发布时间】:2009-09-16 19:29:18
【问题描述】:

在声明二维数组时

int random[height][width];

然后在函数中使用它

void populate(int random[height][width], int x, int y)

给出在任何函数之外声明的错误可变大小类型。 我知道我做错了什么,而且这是一件小事。我只是记性不好……

【问题讨论】:

    标签: c++ compiler-construction function declare


    【解决方案1】:

    我现在要站出来告诉你,多维数组不值得在 C 或 C++ 中花费脑力。最好使用一维数组(或者,更好的是标准容器)并编写索引函数:

    inline int index (int x, int y)
    {
      return x + y * width;
    }
    

    现在解决您的问题。 C++ 不支持 C99 可变长度数组。编译器必须在编译时知道数组的大小。例如,以下内容将不起作用。

    int dim = 4;
    int ar[dim];
    

    如果dimconst,它会起作用,因为编译器能够准确判断ar 的宽度(因为dim 的值不会改变)。这可能是您遇到的问题。

    如果您希望能够在编译时更改大小,则需要做一些更困难的事情,例如编写模板化引用。您不能将指针用于多维数组,因为它们在 C/C++ 中的布局方式。一个模板化的例子可能看起来像下面的异常:

    template <int Width, int Height>
    void populate(int (&(&random)[Width])[Height], int x, int y);
    

    这太丑了。

    对于运行时,您需要使用new 来分配数据,或使用容器类型。

    【讨论】:

    • 我已经将数组的维度更改为常量,但仍然出现错误。
    • 迈克,我认为如果您可以发布导致编译器出错的最少代码会更有帮助。因为int random[25][80] 看起来完全合法。
    • coppro,您的模板如何帮助在运行时更改尺寸? ;-)
    • Mike,请把整个程序缩短 ;-)
    • 您的模板有一个对数组引用的引用作为参数。这在 C++ 中是非法的。
    【解决方案2】:

    您不能在函数之外定义具有非常量维度(宽度、高度)的数组,也就是说 - 不在堆栈帧中,因为在编译时维度是未知的。您可以使用常量或动态分配它(在堆中或堆栈帧中)。

    【讨论】:

      【解决方案3】:

      当数组作为参数直接传递给函数(按值传递)时,它会衰减为指向数组第一个元素的指针。即使您可以在签名中清楚地读取数组的维度,编译器也会忽略这些维度。这种行为与 C 兼容。

      使用 C++,您可以通过引用传递数组,这将不再是问题。

      int extract_value( int (&a)[10][10], int row, int col ) {
         return a[row][col];
      }
      int main() {
         int a[10][10] = {};
         a[5][5] = 1;
         std::cout << extract_value( a, 5, 5 ) << std::endl;
         int b[5][5];
      //   extract_value( b, 2, 2 ); // error: the function takes an array of 10x10
      }
      

      函数参数必须完全匹配,即它只需要一个10x10元素的数组。您可以通过在数组大小上模板化函数来摆脱该限制。一旦你在它也类型:

      template <typename T, int Rows, int Cols>
      T extract_value( T (&a)[Rows][Cols], int row, int col ) {
         return a[row][col];
      }
      int main() {
         int a[5][7] = {};
         extract_value( a, 3, 4 );
         int b[8][2] = {};
         extract_value( b, 7, 1 ); // correct, the compiler matches sizes
         double c[4][4] = {};
         extract_value( c, 2, 2 ); // different types are allowed
      }
      

      这个解决方案仍然很麻烦,因为大小必须是编译时常量,并且数组必须是堆栈分配的。对此的解决方案是定义一些类,该类在缓冲区(线性)中获取动态内存,并从 N 坐标系转换为一维数组以获得值,如前所述。您可以在此 FAQ 中获得有关如何执行此操作的一些提示,该操作符重载提供了 2D 矩阵的实现。一旦你实现了它,你就可以将它用作函数/方法的参数。

      我的建议是遵循最后一条路径:将 N 维数组封装到一个类中,该类提供到一维向量的转换(C++FAQ lite 使用原始指针,我更喜欢 STL 容器)。

      【讨论】:

        【解决方案4】:

        我将用一个例子来说明:

        //全局变量

        const int ARRAY_SIZE = 16 struct ArrayType_t arrayType[ARRAY_SIZE];

        即使 ARRAY_SIZE 被声明为常量 int,它的值也不会在编译时初始化,因此编译器不知道数组的大小并给出这样的错误。但是,如果您将其作为哈希定义 #define ARRAY_SIZE 16 struct ArrayType_t arrayType[ARRAY_SIZE] ===> 因为 ARRAY_SIZE 定义在 编译时和编译器可以在编译时知道数组的大小。

        【讨论】:

          【解决方案5】:

          你可以这样使用:

          void populate(int height, int width, int **random)
          {
              //here you can work from random[0][0] to random[height][width]
          }
          

          那么你可以这样使用它:

          int main()
          {
              int height=10;
              int width=20;
              int **myarray = new int*[height];
              for( int i=0; i< height; i++ ) myarray[i] = new int[width];
              populate( height, width, myarray);
          }
          

          但是,当然,您必须注意缓冲区溢出

          【讨论】:

          • 不,您不能将多维数组作为** 传递。为此,您必须有一个指针数组。
          猜你喜欢
          • 2014-06-25
          • 2020-08-16
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-11-10
          • 1970-01-01
          相关资源
          最近更新 更多