试图创建动态数组

时间:2016-09-07 13:44:56

标签: c++ arrays memory dynamic runtime

我有以下代码,只占整个代码的一半:

// Declare map elements using an enumeration
enum entity_labels {
    EMPTY = 0,
    WALL
};
typedef entity_labels   ENTITY;

// Define an array of ASCII codes to use for visualising the map
const int TOKEN[2] = {
    32,     // EMPTY
    178     // WALL
};

// create type aliases for console and map array buffers

using GUI_BUFFER = CHAR_INFO[MAP_HEIGHT][MAP_WIDTH];
using MAP_BUFFER = ENTITY[MAP_HEIGHT][MAP_WIDTH];

//Declare application subroutines
void InitConsole(unsigned int, unsigned int);
void ClearConsole(HANDLE hStdOut);
WORD GetKey();
void DrawMap(MAP_BUFFER & rMap);


/**************************************************************************
  * Initialise the standard output console
  */
HANDLE  hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
if (hStdOut != INVALID_HANDLE_VALUE)
{
    ClearConsole(hStdOut);

    // Set window title
    SetConsoleTitle(TEXT("Tile Map Demo"));

    // Set window size
    SMALL_RECT srWindowRect;
    srWindowRect.Left = 0;
    srWindowRect.Top = 0;
    srWindowRect.Bottom = srWindowRect.Top + MAP_HEIGHT;
    srWindowRect.Right = srWindowRect.Left + MAP_WIDTH;

    SetConsoleWindowInfo(hStdOut, true, &srWindowRect);

    // Set screen buffer size
    COORD cWindowSize = { MAP_WIDTH, MAP_HEIGHT };
    SetConsoleScreenBufferSize(hStdOut, cWindowSize);
}
/*************************************************************************/


/*************************************************************************
* Initialise the tile map with appropriate ENTITY values
*/

MAP_BUFFER tileMap;

for (unsigned int row = 0; row < MAP_HEIGHT; row++)
{
    for (unsigned int col = 0; col < MAP_WIDTH; col++)
    {
        tileMap [row][col] = WALL;
    }
}

基本上整个代码用于创建一个tile map并将其输出到screen,但我试图在运行时使tileMap成为一个动态数组。 我尝试在创建tileMap的地方创建一个。 我已经尝试在“entity_lables”被赋予typedef“ENTITY”之后创建一个。 我尝试在“MAP_BUFFER”和“GUI_BUFFER”成为别名后创建一个。 但是我仍然感到茫然,我不知道如何成功地将一个动态数组实现到tileMap,我当然不知道最好的位置。

非常感谢任何帮助。

1 个答案:

答案 0 :(得分:0)

用于定义数组的语法是用于恒定大小的C数组。通常,除非在编译时确定数据的大小(并且永远不需要更改),否则应该回避C数组,并且数组永远不会离开作用域(因为C数组不保留有关其自身大小的信息。)< / p>

我建议使用Vector容器来代替常量或动态大小的C数组。 Vector是一个动态大小的容器,从后面填充,是你添加到

的最后一个元素
std::vector<std::vector<ENTITY>>

要将矢量容器添加到项目中,请添加

#include <vector>

要填充容器,您的循环可能如下所示:

MAP_BUFFER tileMap;

for (unsigned int row = 0; row < MAP_HEIGHT; row++)
{
    std::vector<ENTITY> column; // A column of the tile map
    for (unsigned int col = 0; col < MAP_WIDTH; col++)
    {
        column.push_back(WALL); // Add one element to the column
    }
    tileMap.push_back(column); // Add the column to the tile map
}

或者您可以将Vector初始化为您想要的大小,并使用当前循环来指定切片值:

using TILE_MAP = vector<vector<ENTITY>>;
// MAP_WIDTH x MAP_HEIGHT multidimensional vector
TILE_MAP tileMap(MAP_WIDTH, vector<ENTITY>(MAP_HEIGHT)); 

for (unsigned int row = 0; row < MAP_HEIGHT; row++)
{
    for (unsigned int col = 0; col < MAP_WIDTH; col++)
    {
        tileMap [row][col] = WALL;
    }
}

在填充向量之后调用向量的元素具有与数组相同的语法。

tileMap[2][4]

您还可以检查矢量的长度:

int rows = tileMap.size();
if( rows > 0 )
   int columnsInRow0 = tileMap[0].size()

当你在这里时,你应该研究其他容器,比如地图和套装,因为它们可以让你的生活更轻松。

编辑:

由于你想知道如何制作一个不使用矢量的动态数组,我会给你一个答案:std :: vector是C ++定义的动态大小的数组。 C数组在定义后不会改变大小,矢量将会。

但是我认为你问的是定义运行时常量大小的数组的能力。所以我会解释它们是什么以及为什么你不应该使用它们。

当您定义C数组时,您可能会收到一条警告,指出表达式需要保持不变。

C数组是指向堆栈的指针。而且编译时C数组的实现是它在编译时需要是一个常量。

int compiletimeArray[] = { 1, 2, 3 };
// turns out c arrays are pointers
int* ptr = compiletimeArray;
// prints 2
std::cout << compiletimeArray[1];
// prints 2
std::cout << ptr[1];
// prints 2
std::cout << *(compiletimeArray + 1);
// also prints 2
std::cout << *(ptr + 1); //move pointer 1 element and de-reference

指针就像一块白板,上面写着电话号码。出现与电话号码相同的问题;白板上的号码已被删除,白板上的号码已更改,收件人不存在,收件人更改了号码,服务提供商用尽了可用的号码给新用户...请记住这一点。

要创建运行时常量大小的数组,您需要在堆上分配数组并将其分配给指针。

int size = 4;
int* runtimeArray = new int[size];           // this will work
delete[] runtimeArray;                       // de-allocate
size = 8;                                    // change size
runtimeArray = new int[size];                // allocate a new array

堆栈和堆栈之间的主要区别在于,当程序退出变量声明的作用域时,堆栈将取消分配变量使用的内存,另一方面,堆上声明的任何内容仍将保留在内存并且必须明确地取消分配,否则会出现内存泄漏。

 // You must call this when you are never going to use the data at the memory address again
 // release the memory from the heap
 delete[] runtimeArray; // akin to releasing a phone number to be used by someone else

如果你没有从堆中释放内存,那么你将耗尽。

 // Try running this
 void crashingFunction() {
   while(true)
   {
       // every time new[] is called ptr is assigned a new address, the memory at the old address is not freed
       // 90001 ints worth of space(generally 32 or 64 bytes each int) is reserved on the heap
       int* ptr = new int[90001]; // new[] eventually crashes because your system runs out of memory space to give
   }
 }

 void okFunction() {
   // Try running this
   while(true)
   {
       // every time new[] is called ptr is assigned a new address, the old is not freed
       // 90001 ints worth of space is reserved on the heap
       int* ptr = new int[90001]; // never crashes
       delete[] ptr; // reserved space above is de-allocated 
   }
 }

为什么要使用std :: vector?因为std :: vector在内部管理运行时数组。

 // allocates for you
 vector(int size) {
      // ...
      runtimeArray = new runtimeArray[size];
 }

 // When the vector exits scope the deconstructor is called and it deletes allocated memory
 //   So you do not have to remember to do it yourself
 ~vector() { 
      // ...
      delete[] runtimeArray;
 }

所以,如果你有与上次相同的情景

 void vectorTestFunction() {
   // Try running this
   while(true)
   {
       std::vector<int> vec(9001); // internally allocates memory
   } // <-- deallocates memory here because ~vector is called
 }

如果你想使用运行时常量数组,我建议使用std:array容器。它就像矢量一样,它管理着它的内部存储器,但如果你永远不需要添加新的元素就会进行优化。它被声明为vector,但在构造函数之后不包含resizing函数。