C ++数组大小初始化

时间:2012-06-04 18:52:49

标签: c++ arrays memory-management

我正在尝试定义一个类。这就是我所拥有的:

enum Tile {
GRASS, DIRT, TREE 
};

class Board {
public:
    int toShow;
    int toStore;
    Tile* shown;
    Board (int tsh, int tst);
    ~Board();
};

Board::Board (int tsh, int tst) {
    toShow = tsh;
    toStore = tst;
    shown = new Tile[toStore][toStore]; //ERROR!
}

Board::~Board () {
    delete [] shown;
}

但是,我在指示的行上出现以下错误 - 只有已分配数组的第一个维可以具有动态大小。

我想要做的就是硬编码,将参数toShow传递给构造函数并创建一个二维数组,其中只包含我想要显示的元素。

但是,我的理解是,当调用构造函数并显示初始化时,其大小将初始化为toStore的当前值。然后,即使存储更改,内存也已分配给显示的数组,因此大小不应更改。但是,编译器并不喜欢这样。

对于我如何理解这一点,是否存在真正的误解?有没有人有一个修复程序,可以做我想要的,而无需硬编码数组的大小?

5 个答案:

答案 0 :(得分:3)

使用C ++的容器,这就是他们的目的。

class Board {
public:
    int toShow;
    int toStore;
    std::vector<std::vector<Tile> > shown;
    Board (int tsh, int tst) : 
      toShow(tsh), toStore(tst), 
      shown(tst, std::vector<Tile>(tst))
    {
    };
};

...

    Board board(4, 5);
    board.shown[1][3] = DIRT;

答案 1 :(得分:2)

您可以使用一维数组。您应该知道二维数组被视为一维数组,当您想要一个可变大小时,您可以使用此模式。例如:

int arr1[ 3 ][ 4 ] ;
int arr2[ 3 * 4 ] ;

它们是相同的,可以通过不同的符号访问其成员:

int x = arr1[ 1 ][ 2 ] ;
int x = arr2[ 1 * 4 + 2 ] ;

当然,arr1可以看作是3行x 4 cols矩阵和3 col x 4行矩阵。 使用这种类型的多维数组,您可以通过单个指针访问它们,但您必须了解其内部结构。它们是一维阵列,它们被视为2维或3维。

答案 2 :(得分:1)

让我告诉你我在需要3D阵列时所做的事情。这可能是一个过度的,但它很酷,可能会有所帮助,虽然这是一种完全不同的方式来做你想做的事。

我需要代表3D盒子的细胞。只有一部分细胞被标记出来并且是有意义的。有两种选择可以做到这一点。第一个,声明一个具有最大可能尺寸的静态3D数组,如果框的一个或多个尺寸小于静态数组中的相应尺寸,则使用它的一部分。

第二种方法是动态分配和释放数组。使用2D阵列非常省力,更不用说3D了。

阵列解决方案定义了一个3D阵列,其中感兴趣的细胞具有特殊值。大部分分配的内存都是不必要的。

我甩了两路。相反,我转向STL地图。 我定义了一个名为Cell的结构,它有3个成员变量,x,y,z代表坐标。构造函数Cell(x, y, z)用于轻松创建这样的Cell。 我在其上定义operator <以使其可订购。然后我定义了一个map<Cell, Data>。将带有坐标x,y,z的标记单元格添加到地图中仅通过

完成

my_map[Cell(x, y, z)] = my_data;

这样我就不需要维护3D阵列内存管理,也只需要实际创建所需的单元。

检查坐标x0,y0,z0上的呼叫是否存在(或标记)是由:

map<Cell, Data>::iterator it = my_map.find(Cell(x0, y0, z0));
if (it != my_map.end()) { ...

在协调x0,y0,z0引用单元格的数据是通过以下方式完成的: my_map[Cell(x0, y0, z0)]...

这种方法可能看起来很奇怪,但它很强大,对内存有自我管理,而且安全 - 没有边界超限。

答案 3 :(得分:0)

首先,如果要引用2D数组,则必须声明指向指针的指针:

Tile **shown;

然后,看一下错误信息。这是正确的,可理解的英语。它说错误是什么。 Only the first dimension of an allocated array can have dynamic size.表示 - 猜测,只有已分配数组的第一维可以具有动态大小。而已。如果您希望矩阵具有多个动态维度,请使用C样式malloc()来维护指针指针,或者对于C ++更好,使用vector,完全是为了这个目的。

答案 4 :(得分:0)

了解内存分配在C和C ++中的工作原理很好。

char x[10];

编译器将分配十个字节并记住起始地址,也许它位于0x12(在现实生活中可能是一个更大的数字。)

x[3] = 'a';

现在编译器通过取x[3]的起始地址x并添加0x12来查找3*sizeof(char),这会带来0x15。因此x[3]生活在0x15

这个简单的加法运算是如何访问数组中的内存。对于二维数组,数学只是稍微复杂一点。

char xy[20][30];

从某个地方开始分配600个字节,也许是0x2000。现在访问

xy[4][3];

需要一些数学...... xy[0][0], xy[0][1], xy[0][2]...将占用前30个字节。然后xy[1][0], xy[1][1], ...将占用字节31到60.它是乘法:xy[a][b]将位于xy的地址,加上* 20,加上b。

这只有在编译器知道第一个维度有多长时才有可能 - 你会注意到编译器需要知道数字“20”才能进行数学运算。

现在进行函数调用。编译器很少关心你是否调用

foo(int* x);

foo(int[] x);

因为在任何一种情况下它都是一个字节数组,你传递起始地址,编译器可以做额外的事情来找到x[3]或其他任何生命的地方。但是在二维数组的情况下,编译器需要知道上面示例中的幻数20。所以

foo(int[][] xy) {
    xy[3][4] = 5;     //compiler has NO idea where this lives 
                      //because it doesn't know the row dimension of xy!
}

但是如果你指定

foo(int[][30] xy)

编译器知道该怎么做。由于我不记得的原因,将它作为双指针传递通常被认为是更好的做法,但这正是技术层面上发生的事情。