This code works fine in VS2010 but now I am trying to port it to my mac with xcode 4.6 and it's giving me some bad access errors at run time. Basically I have a board class which contains a 2d array of tiles, when I create the board I can access the tiles functions but when I later run my draw function it gives me bad access. Here is a sample of my board class.
Board.h
#include "Tile.h"
class Board
{
private:
//This is the GameBoard of a 2D array of Tiles
Tile *** GameBoard;
void CreateBoard(const int size);
void FillValues();
...
public:
Board(int size);
void DrawBoard();
...
}
Board.cpp
Board::Board(const int size)
{
won=false;
lost=false;
BoardSize =size;
GameBoard = new Tile**[size];
CreateBoard(size);
}
void Board::CreateBoard(const int size)
{
...
FillValues()
}
void Board::FillValues()
{
for(int x=1;x<BoardSize+1;x++)
{
for(int y =1;y<BoardSize+1;y++)
{
if (GameBoard[x][y]->Type()=="NumberTile")
{
int neighbors = CountNeighbours(x,y);
GameBoard[x][y]->SetValue(neighbors);
//This works
}
}
}
}
void Board::DrawBoard()
{
for(int i=0;i<=BoardSize+1;i++)
{
for (int j=0;j<=BoardSize+1;j++)
{
if (GameBoard[i][j]->Type() != "BorderTile") {
GameBoard[i][j]->Draw();
//This does not work, i get the error when it tries to use ->Type()
}
}
}
}
...
I call the functions like this
GI = new Board(SCREEN_SIZE);
GI->DrawBoard();
GameBoard = new Tile**[size];
This just creates an array of Tile**. You don't yet have any actual Tiles or even Tile*s and later, when you're trying to access elements of the array with GameBoard[x][y]->, you're hitting undefined behaviour.
As you have it, you would need to do this:
GameBoard = new Tile**[size]; // Allocate an array of Tile**
for (int i = 0; i < size; i++) {
GameBoard[i] = new Tile*[size]; // Allocate an array of Tile*
for (int j = 0; i < size; j++) {
GameBoard[i][j] = new Tile(); // Allocate an array of Tile
}
}
However, this is awful. It's three lots of dynamic allocation that you have to remember to tidy up at the end (and tidy up correctly).
A simpler approach would be to just have an 2D array of tiles:
Tile GameBoard[CONSTEXPR_SIZE][CONSTEXPR_SIZE];
Or better yet, use the std::array container:
std::array<std::array<Tile, CONSTEXPR_SIZE>, CONSTEXPR_SIZE> GameBoard;
Here, the size given has to be a constant expression. If you need it to be dynamically sized, use a std::vector instead.
In the comments below, you say the size of your array is actually BoardSize+1. Still, you are iterating over too many elements in both your outer and inner for loops:
for(int i=0;i<=BoardSize+1;i++)
This should be:
for(int i=0; i<BoardSize+1; i++)
Also in the comments below, you say that Type returns a char*. That means you can't do your string comparison like this:
GameBoard[i][j]->Type() != "BorderTile"
This simply performs pointer comparison, since the left operand is a char* and the right operand is convertible to const char*. It doesn't compare the strings themselves. Instead, you want:
GameBoard[i][j]->Type() != std::string("BorderTile")
This will force std::string comparison to be used.
Related
Software: Visual Studio 2017 Community
Hi, everybody,
I am making a simple 2d console game in C++ (perhaps very simplified Dwarf Fortress if you know it).
And I want a map to be displayed in console with ASCII.
Something like this:
I have a WorldMap class declared in the header file(simplified version).
And I declare a 2d array inside it.
#pragma once
#include <iostream>
class WorldMap
{
public:
WorldMap();
virtual ~WorldMap();
private:
int worldWidth;
int worldHeight;
char worldMap; // Declare a variable that will hold all the characters for the map
};
And then define it in the .cpp file:
#include "WorldMap.h"
#include <algorithm>
WorldMap::WorldMap()
{
worldWidth = 50;
worldHeight = 50;
worldMap[50][50]; // Define the map array
// And then here I will also somehow need to be able to fill the whole map with '.' symbols, and so on
}
So that is the basic idea of what I am trying to achieve. The reason why I can't define the array size immediately is because I want to be able to choose the size of the map when the map is created.
I have already tried:
The code above.
Error:
error C2109: subscript requires array or pointer type
Declaring 2d array as char worldMap[][]; and then defining it as worldMap[50][50]; .
Error:
error C2087: 'worldMap': missing subscript
warning C4200: nonstandard extension used: zero-sized array in struct/union
message : This member will be ignored by a defaulted constructor or copy/move assignment operator
Declaring 2d array as char worldMap[worldWidth][worldHeight];, expecting that when the object is created, the width and height variables will be defined first, and then they will define the array.
Error:
error C2327: 'WorldMap::worldWidth': is not a type name, static, or enumerator
error C2065: 'worldWidth': undeclared identifier
error C2327: 'WorldMap::worldHeight': is not a type name, static, or enumerator
error C2065: 'worldHeight': undeclared identifier
Using char* worldMap; and char** worldMap, but so far I can't even understand how double pointer works, yet char* worldMap actually works with a 1D array without errors, until I start accessing values of the elements in the array.
I suppose a workaround would be to use a string or 1D char array and when displaying it just use mapWidth to end line each 50 characters for example, which will give the same result. But I feel like that's not a good way to achieve this since I will need to access x and y coords of this map and so on.
I guess what I am asking is:
What's the best way of declaring a 2d array for a class and then defining it in the object?
What's the best way to store a map for such a console game? (Not necessarily using arrays)
Thank you for reading. I will really appreciate any help, even just ideas and tips might push me in the right direction :)
What's the best way of declaring a 2d array for a class and then defining it in the object?
What's the best way to store a map for such a console game? (Not necessarily using arrays)
This is not "the best way" but it's one way of doing it.
Create a class wrapping a 1D std::vector<char>.
Add operator()s to access the individual elements.
Add misc. other support functions to the class, like save() and restore().
I've used your class as a base and tried to document what it's doing in the code: If some of the functions I've used are unfamiliar, I recommend looking them up at https://en.cppreference.com/ which is an excellent wiki that often has examples of how to use the particular function you read about.
#include <algorithm> // std::copy, std::copy_n
#include <filesystem> // std::filesystem::path
#include <fstream> // std::ifstream, std::ofstream
#include <iostream> // std::cin, std::cout
#include <iterator> // std::ostreambuf_iterator, std::istreambuf_iterator
#include <vector> // std::vector
class WorldMap {
public:
WorldMap(unsigned h = 5, unsigned w = 5) : // colon starts the initializer list
worldHeight(h), // initialize worldHeight with the value in h
worldWidth(w), // initialize worldWidth with the value in w
worldMap(h * w, '.') // initialize the vector, size h*w and filled with dots.
{}
// Don't make the destructor virtual unless you use polymorphism
// In fact, you should probably not create a user-defined destructor at all for this.
//virtual ~WorldMap(); // removed
unsigned getHeight() const { return worldHeight; }
unsigned getWidth() const { return worldWidth; }
// Define operators to give both const and non-const access to the
// positions in the map.
char operator()(unsigned y, unsigned x) const { return worldMap[y*worldWidth + x]; }
char& operator()(unsigned y, unsigned x) { return worldMap[y*worldWidth + x]; }
// A function to print the map on screen - or to some other ostream if that's needed
void print(std::ostream& os = std::cout) const {
for(unsigned y = 0; y < getHeight(); ++y) {
for(unsigned x = 0; x < getWidth(); ++x)
os << (*this)(y, x); // dereference "this" to call the const operator()
os << '\n';
}
os << '\n';
}
// functions to save and restore the map
std::ostream& save(std::ostream& os) const {
os << worldHeight << '\n' << worldWidth << '\n'; // save the dimensions
// copy the map out to the stream
std::copy(worldMap.begin(), worldMap.end(),
std::ostreambuf_iterator<char>(os));
return os;
}
std::istream& restore(std::istream& is) {
is >> worldHeight >> worldWidth; // read the dimensions
is.ignore(2, '\n'); // ignore the newline
worldMap.clear(); // empty the map
worldMap.reserve(worldHeight * worldWidth); // reserve space for the new map
// copy the map from the stream
std::copy_n(std::istreambuf_iterator<char>(is),
worldHeight * worldWidth, std::back_inserter(worldMap));
return is;
}
// functions to save/restore using a filename
bool save(const std::filesystem::path& filename) const {
if(std::ofstream ofs(filename); ofs) {
return static_cast<bool>(save(ofs)); // true if it suceeded
}
return false;
}
bool restore(const std::filesystem::path& filename) {
if(std::ifstream ifs(filename); ifs) {
return static_cast<bool>(restore(ifs)); // true if it succeeded
}
return false;
}
private:
unsigned worldHeight;
unsigned worldWidth;
// Declare a variable that will hold all the characters for the map
std::vector<char> worldMap;
};
Demo
There is no best way to do anything*. It's what works best for you.
From what I understand you want to make a dynamic 2D arrays to hold your char of world map. You have a lot of options to do this. You can have a worldMap class nothing wrong with that. If you want dynamic 2D arrays just make functions out of this kind of logic.
#include <iostream>
#include <vector>
int main() {
int H = 10, W = 20;
char** map = NULL; //This would go in your class.H
//Make a function to allocate 2D array
map = new char* [H];
for (int i = 0; i < H; i++) {
map[i] = new char[W];
}
//FILL WITH WHATEVER
for (int i = 0; i < H; i++) {
for (int j = 0; j < W; j++) {
map[i][j] = 'A';
}
}
//do what ever you want like normal 2d array
for (int i = 0; i < H; i++) {
for (int j = 0; j < W; j++) {
std::cout << map[i][j] << " ";
}
std::cout << std::endl;
}
//Should always delete when or if you want to make a new one run time
for (int i = 0; i < H; i++)
delete[] map[i];
delete[] map;
map = NULL;
//Also you can use vectors
std::cout << "\n\n With vector " << std::endl;
std::vector<std::vector<char>> mapV;
//FILL WITH WHATEVER
for (int i = 0; i < H; i++) {
std::vector<char> inner;
for (int j = 0; j < W; j++) {
inner.push_back('V');
}
mapV.push_back(inner);
}
//do what ever you want kind of like a normal array
//but you should look up how they really work
for (int i = 0; i < H; i++) {
for (int j = 0; j < W; j++) {
std::cout << mapV[i][j] << " ";
}
std::cout << std::endl;
}
mapV.clear();
return 0;
}
I'm new with using classes and I encountered a problem while delcaring an array into a class. I want to initialize a char array for text limited to 50 characters and then replace the text with a function.
#ifndef MAP_H
#define MAP_H
#include "Sprite.h"
#include <SFML/Graphics.hpp>
#include <iostream>
class Map : public sprite
{
private:
char mapname[50];
int columnnumber;
int linenumber;
char casestatematricia[];
public:
void setmapname(char newmapname[50]);
void battlespace(int column, int line);
void setcasevalue(int col, int line, char value);
void printcasematricia();
};
#endif
By the way I could initialize my 2d array like that
char casestatematricia[][];
I want later to make this 2d array dynamic where I enter a column number and a line number like that
casestatematricia[linenumber][columnnumber]
to create a battlefield.
this is the cpp code so that you have an idea of what I want to do.
#include "Map.h"
#include <SFML/Graphics.hpp>
#include <iostream>
using namespace sf;
void Map::setmapname(char newmapname[50])
{
this->mapname = newmapname;
}
void Map::battlespace(int column, int line)
{
}
void Map::setcasevalue(int col, int line, char value)
{
}
void Map::printcasematricia()
{
}
thank you in advance.
Consider following common practice on this one.
Most (e.g. numerical) libraries don't use 2D arrays inside classes.
They use dynamically allocated 1D arrays and overload the () or [] operator to access the right elements in a 2D-like fashion.
So on the outside you never can tell that you're actually dealing with consecutive storage, it looks like a 2D array.
In this way arrays are easier to resize, more efficient to store, transpose and reshape.
Just a proposition for your problem:
class Map : public sprite
{
private:
std::string mapname;
int columnnumber;
int linenumber;
std::vector<char> casestatematricia;
static constexpr std::size_t maxRow = 50;
static constexpr std::size_t maxCol = 50;
public:
Map():
casestatematricia(maxRow * maxCol, 0)
{}
void setmapname(std::string newmapname)
{
if (newmapname.size() > 50)
{
// Manage error if you really need no more 50 characters..
// Or just troncate when you serialize!
}
mapname = newmapname;
}
void battlespace(int col, int row);
void setcasevalue(int col, int row, char value)
{
// check that col and line are between 0 and max{Row|Column} - 1
casestatematricia[row * maxRow + col] = value;
}
void printcasematricia()
{
for (std::size_t row = 0; row < maxRow; ++row)
{
for (std::size_t col = 0; col < maxCol; ++col)
{
char currentCell = casestatematricia[row * maxRow + col];
}
}
}
};
For access to 1D array like a 2D array, take a look at Access a 1D array as a 2D array in C++.
When you think about serialization, I guess you want to save it to a file. Just a advice: don't store raw memory to a file just to "save" time when your relaunch your soft. You just have a non portable solution! And seriously, with power of your computer, you don't have to be worry about time to load from file!
I propose you to add 2 methods in your class to save Map into file
void dump(std::ostream &os)
{
os << mapname << "\n";
std::size_t currentRow = 0;
for(auto c: casestatematricia)
{
os << static_cast<int>(c) << " ";
++currentRow;
if (currentRow >= maxRow)
{
currentRow = 0;
os << "\n";
}
}
}
void load(std::istream &is)
{
std::string line;
std::getline(is, line);
mapname = line;
std::size_t current_cell = 0;
while(std::getline(is, line))
{
std::istringstream is(line);
while(!is.eof())
{
char c;
is >> c;
casestatematricia[current_cell] = c;
++current_cell;
}
}
}
This solution is only given for example. They doesn't manage error and I have choose to store it in ASCII in file. You can change to store in binary, but, don't use direct write of raw memory. You can take a look at C - serialization techniques (just have to translate to C++). But please, don't use memcpy or similar technique to serialize
I hope I get this right. You have two questions. You want know how to assign the value of char mapname[50]; via void setmapname(char newmapname[50]);. And you want to know how to create a dynamic size 2D array.
I hope you are comfortable with pointers because in both cases, you need it.
For the first question, I would like to first correct your understanding of void setmapname(char newmapname[50]);. C++ functions do not take in array. It take in the pointer to the array. So it is as good as writing void setmapname(char *newmapname);. For better understanding, go to Passing Arrays to Function in C++
With that, I am going to change the function to read in the length of the new map name. And to assign mapname, just use a loop to copy each of the char.
void setmapname(char *newmapname, int length) {
// ensure that the string passing in is not
// more that what mapname can hold.
length = length < 50 ? length : 50;
// loop each value and assign one by one.
for(int i = 0; i < length; ++i) {
mapname[i] = newmapname[i];
}
}
For the second question, you can use vector like what was proposed by Garf365 need to use but I prefer to just use pointer and I will use 1D array to represent 2d battlefield. (You can read the link Garf365 provide).
// Declare like this
char *casestatematricia; // remember to initialize this to 0.
// Create the battlefield
void Map::battlespace(int column, int line) {
columnnumber = column;
linenumber = line;
// Clear the previous battlefield.
clearspace();
// Creating the battlefield
casestatematricia = new char[column * line];
// initialise casestatematricia...
}
// Call this after you done using the battlefield
void Map::clearspace() {
if (!casestatematricia) return;
delete [] casestatematricia;
casestatematricia = 0;
}
Just remember to call clearspace() when you are no longer using it.
Just for your benefit, this is how you create a dynamic size 2D array
// Declare like this
char **casestatematricia; // remember to initialize this to 0.
// Create the battlefield
void Map::battlespace(int column, int line) {
columnnumber = column;
linenumber = line;
// Clear the previous battlefield.
clearspace();
// Creating the battlefield
casestatematricia = new char*[column];
for (int i = 0; i < column; ++i) {
casestatematricia[i] = new char[line];
}
// initialise casestatematricia...
}
// Call this after you done using the battlefield
void Map::clearspace() {
if (!casestatematricia) return;
for(int i = 0; i < columnnumber; ++i) {
delete [] casestatematricia[i];
}
delete [][] casestatematricia;
casestatematricia = 0;
}
Hope this help.
PS: If you need to serialize the string, you can to use pascal string format so that you can support string with variable length. e.g. "11hello world", or "3foo".
I'm new to C++ and I am working on a function to shuffle strings
It takes an array of strings, shuffles them, and returns them back to the main.
I am returning a pointer to an array of strings called shuffled. The problem I have is that when I try to save that new pointer to the array to another pointer in the main, I start getting weird values that either reference to a file location in my computer or a bunch of numbers.
I'll post the entire code here but really what you want to look at is the return types, how I return it and how I save it in main. Please tell me why my pointer is not referencing the working array that is created in the function. Here's the code:
#include <cstdio>
#include <string>
#include <ctime>
#include <new>
#include <cstdlib>
using namespace std;
const char * getString(const char * theStrings[], unsigned int stringNum)
{
return theStrings[stringNum];
}
string * shuffleStrings(string theStrings[])
{
int sz = 0;
while(!theStrings[sz].empty())
{
sz++;
}
sz--;
int randList[sz];
for(int p = 0; p < sz; p++)
{
randList[p] = sz;
}
srand(time(0));//seed randomizer to current time in seconds
bool ordered = true;
while(ordered)
{
int countNumberInRandList = 0;//avoid having a sz-1 member list length (weird error I was getting)
for(int i = 0; i < sz; i++)
{
int count = 0;
int randNum = rand()%(sz+1);//get random mod-based on size
for(int u = 0; u < sz; u++)
{
if(randList[u] != randNum)
{
count++;
}
}
if(count == sz)
{
randList[i] = randNum;
countNumberInRandList++;
}
else
i--;
}
//check to see if order is same
int count2 = 0;
for(int p = 0; p < sz; p++)
{
if(randList[p] == p)
{
count2++;
}
}
if(count2 < sz-(sz/2) && countNumberInRandList == sz)
{
ordered = false;
}
}
string * shuffled[sz];
for(int r = 0; r < sz; r++) //getting random num, and str list pointer from passed in stringlist and setting that value at shuffled [ random ].
{
int randVal = randList[r];
string * strListPointer = &theStrings[r];
shuffled[randVal] = strListPointer;
}
for(int i = 0; i < sz; i++)
{
printf("element %d is %s\n", i, shuffled[i]->c_str());//correct values in a random order.
}
return *shuffled;
}
int main()
{
string theSt[] = {"a", "b", "pocahontas","cashee","rawr", "okc", "mexican", "alfredo"};
string * shuff = shuffleStrings(theSt);//if looped, you will get wrong values
return 0;
}
Strings allocate their own memory, no need to give them the "length" like you would have to do for char arrays. There are several issues with your code - without going into the details, here are a few working/non-working examples that will hopefully help you:
using std::string;
// Returns a string by value
string s1() {
return "hello"; // This implicitly creates a std::string
}
// Also returns a string by value
string s2() {
string s = "how are you";
return s;
}
// Returns a pointer to a string - the caller is responsible for deleting
string* s3() {
string* s = new string;
*s = "this is a string";
return s;
}
// Does not work - do not use!
string* this_does_not_work() {
string s = "i am another string";
// Here we are returning a pointer to a locally allocated string.
// The string will be destroyed when this function returns, and the
// pointer will point at some random memory, not a string!
// Do not do this!
return &s;
}
int main() {
string v1 = s1();
// ...do things with v1...
string v2 = s2();
// ...do things with v2...
string* v3 = s3();
// ...do things with v3...
// We now own v3 and have to deallocate it!
delete v3;
}
There are a bunch of things wrong here -- don't panic, this is what happens to most people when they are first wrapping their brains around pointers and arrays in C and C++. But it means it's hard to put a finger on a single error and say "this is it". So I'll point out a few things.
(But advance warning: You ask about the pointer being returned to main, your code does indeed do something wrong with that, and I am about to say a bunch of things about what's wrong and how to do better. But that is not actually responsible for the errors you're seeing.)
So, in shuffleStrings you're making an array of pointers-to-string (string * shuffled[]). You're asking shuffleStrings to return a single pointer-to-string (string *). Can you see that these don't match?
In C and C++, you can't actually pass arrays around and return them from functions. The behaviour you get when you try tends to be confusing to newcomers. You'll need to understand it at some point, but for now I'll just say: you shouldn't actually be making shuffleStrings try to return an array.
There are two better approaches. The first is to use not an array but a vector, a container type that exists in C++ but not in C. You can pass arrays around by value, and they will get copied as required. If you made shuffleStrings return a vector<string*> (and made the other necessary changes in shuffleStrings and main to use vectors instead of arrays), that could work.
vector<string *> shuffleStrings(...) {
// ... (set things up) ...
vector<string *> shuffled(sz);
// ... (fill shuffled appropriately) ...
return shuffled;
}
But that is liable to be inefficient, because your program is then having to copy a load of stuff around. (It mightn't be so bad in this case, because a smallish array of pointers isn't very large and because C++ compilers are sometimes able to figure out what you're doing in cases like this and avoid the copying; the details aren't important right now.)
The other approach is to make the array not in shuffleStrings but in main; to pass a pointer to that array (or to its first element, which turns out to be kinda equivalent) into shuffleStrings; and to make shuffleStrings then modify the contents of the array.
void shuffleStrings(string * shuffled[], ...) {
// ... (set things up) ...
// ... (fill shuffled appropriately) ...
}
int main(...) {
// ...
string * shuffled[sz];
shuffleStrings(shuffled, theSt);
// output strings (main is probably a neater place for this
// than shuffleStrings)
}
Having said all this, the problems that are causing your symptoms lie elsewhere, inside shuffleStrings -- after all, main in your code never actually uses the pointer it gets back from shuffleStrings.
So what's actually wrong? I haven't figured out exactly what your shuffling code is trying to do, but that is where I bet the problem lies. You are making this array of pointers-to-string, and then you are filling in some of its elements -- the ones corresponding to numbers in randList. But if the numbers in randList don't cover the full range of valid indices in shuffled, you will leave some of those pointers uninitialized, and they might point absolutely anywhere, and then asking for their c_strs could give you all kinds of nonsense. I expect that's where the problem lies.
Your problem has nothing to do with any of the stuff you are saying. As you are a beginner I would suggest not presuming that your code is correct. Instead I would suggest removing parts that are not believed to be problematic until you have nothing left but the problem.
If you do this, you should quickly discover that you are writing to invalid memory.
part two : you can't seem to decide on the type of what you are returning. Are you building a pointer to an array to return or are you returning an array of pointers.... you seem to switch between these intermittently.
part three : read #Gareth's answer, he explains about passing parameters around nicely for your instance.
I need a double pointer of type DizzyCreature (my class) to point to an array of DizzyCreature pointers. When I run it I get "Access violation reading location 0x...". I can make a DizzyCreature* and call its member functions just fine, but when cannot run through the array and do the same thing for each obj.
I am following these instructions:
http://www.cplusplus.com/forum/beginner/10377/
Code
Server.h:
class Server
{
public:
Server(int x, int y, int count);
~Server(void);
void tick();
private:
DizzyCreature** dcArrPtr;
DizzyCreature* dcPtr;
int _count;
};
Server.cpp:
Server::Server(int x, int y, int count)
{
dcPtr = new DizzyCreature[count]; // this works just fine
dcArrPtr = new DizzyCreature*[count]; // this doesn't (but gets past this line)
_count = count;
}
Server::~Server(void)
{
delete[] *dcArrPtr;
delete[] dcPtr;
}
void Server::tick()
{
dcPtr->takeTurn(); // just fine
for (int i = 0; i < _count; i++) {
dcArrPtr[i]->takeTurn(); // crash and burn
}
}
EDIT:
The member function takeTurn() is in a parent class of DizzyCreature. The program makes it into the function, but as soon as it attempts to change a private member variable the exception is thrown. If it matters, DizzyCreature is of type GameCreature and WhirlyB as this is an assignment on MI.
You have allocated space for dcArrPtr, but didn't allocate every object in this array. You must do following:
Server::Server(int x, int y, int count)
{
dcPtr = new DizzyCreature[count];
dcArrPtr = new DizzyCreature*[count];
for ( int i = 0; i < count; i++ ) {
dcArrPtr[ i ] = new DizzyCreature;
}
_count = count;
}
Server::~Server(void)
{
for ( int i = 0; i < count; i++ ) {
delete dcArrPtr[ i ];
}
delete[] *dcArrPtr;
delete[] dcPtr;
}
This:
dcPtr = new DizzyCreature[count];
"creates" an array of DizzyCreatures, whereas:
dcArrPtr = new DizzyCreature*[count];
"creates" an array of pointers to DizzyCreatures, but crucially doesn't create instances for those pointers to point to.
The preferred solution is to use a standard container for tasks like this anyway though. If you really want to do it like this (and are aware that it's not best practice to do this manually) then you'll need a loop to call new for eachelement in the array of pointers.
You allocate an array of count pointers instead of an array of count objects.
Instead of
dcArrPtr = new DizzyCreature*[count];
you might want to
dcArrPtr = new DizzyCreature[count];
You're allocating an array of pointers, but those pointers aren't valid until you set them to something.
double **arr = new double*[10];
for(int i=0;i<10;++i) {
arr[i] = new double[10];
}
That said, when starting out with C++ you should probably avoid raw arrays and instead use std::array and std::vector:
class Server
{
public:
Server(int x, int y, int count);
void tick();
private:
std::vector<std::vector<DizzyCreature>> dcArrPtr;
std::vector<DizzyCreature> dcPtr;
};
Server::Server(int x, int y, int count)
{
dcPtr.resize(count);
dcArrPtr.resize(count);
}
void Server::tick()
{
dcPtr[0].takeTurn();
for (int i = 0; i < dcArrPtr.size(); i++) {
dcArrPtr[i][0].takeTurn();
}
}
Use a
std::vector<std::vector<DizzyCreature>>
Furthermore, if you want to use raw pointers (which I do not recommend), you'll have to allocate memory for each pointer in your array.
class A
{
std::vector<std::vector<int>> v_;
public:
A()
: v_(500, std::vector<int>(500))
{} // 500 x 500
};
class B
{
int** v_;
public:
B()
: v_(new int*[500])
{ // not even exception safe
for (int i = 500; i--; )
v_[i] = new int[500];
}
~B()
{
for (int i = 500; i--; )
delete[] v_[i];
delete[] v_;
}
};
If you would have seen the implementation of dynamic memory allocation of 2-Dimensional array . That would have given you a better insight of how to proceed in such cases . Most of the answers has already answered you what to do . But just go through any link and see how is memory allocated in case of 2-D array . That Will also help you .
I'm having some issues deallocating arrays of a class I have. Below is the Class, a simplified implementation and my code I have tried to use to close it.
Characters class
#include <cstdlib>
class Character
{
private:
bool human;
int Xposition; // the character's postion on the board.
int Yposition; // the character's postion on the board.
bool alive;
public:
Character(); //This is my constructor
~Character(); //This is my destructor
bool isHuman(); //return whether type 1 aka Human
bool isZombie(); //return whether type 2 aka Zombie
void setHuman(); //set to type 1 or Human
void setZombie(); //set to type 2 or Zombie
void setPos(int xpos, int ypos); //set the board position
int X();
int Y();
bool isAlive(); //checks to see if a Human is still alive and to be displayed
bool Dead(); //kills the character and sets alive to false
int num_moves_allowed; //number of moves allowed.
};
Allocation code:
Character *characters[11];
int human_count = 0;
for(int i=0; i<12; i++)
{
characters[human_count] = new Character();
human_count++;
}
Termination code:
for(i=11;i<=0;i--)
{
if(characters)
{
characters[i]->~Character();
delete characters[i]; characters[i] = NULL;
}
}
if(characters)
{
//ERROR IS HERE
delete [] characters;
}
I have tried a number of different "delete" commands on the array and I keep getting an "Debug Assertion Failed!" window. It says that the dbgdel.cpp from visual studio vctools is the problem place on Line 52.
It also says "Expression: _BLOCK_TYPE_IS_VALID(pHead->nBlockUse)
Someone please help me I'm sure this is very simple.
I'd suggest you avoid using arrays all together. Use a vector of characters.
Declare your vector as
vector<Character> vCharacters;
then insert objects as
for(int i = 0; i < 100; i++)
vCharacters.push_back(Character());
If you want to store pointers to Character objects then wrap them in a shared_ptr which will take care of deallocating them for you.
vector<shared_ptr<Character>> vCharacters;
for(int i =0; i < 100; i++)
{
shared_ptr<Character> spCharacter(new Character());
vCharacters.push_back(spCharacter);
}
Avoid managing memory yourself when C++ can do it fo ryou
The characters array was allocated on the stack, so you don't have to delete it. However, if you want the array to survive the local scope, create it with something like this:
Character **characters = new Character[11];
then your delete[] line should work fine.
Also note that you don't need to call the destructor of Character explicitly: it is called automatically by delete.
As obelix mentioned, you should use a vector from the Standard Template Library.
However, if you're determined to use a raw array:
const int MAX_CHARACTERS = 11;
Character *characters[MAX_CHARACTERS];
for(int characterCount = 0; characterCount < MAX_CHARACTERS; ++characterCount)
{
characters[characterCount] = new Character();
}
...
if (characters != NULL)
{
for(int i = 0; i < MAX_CHARACTERS; ++i)
{
delete characters[i];
}
}
Paolo Capriotti is correct that characters should be declared with new if you want it to last beyond its scope:
const int MAX_CHARACTERS = 11;
Character **characters = new Character*[MAX_CHARACTERS];
for(int characterCount = 0; characterCount < MAX_CHARACTERS; ++characterCount)
{
characters[characterCount] = new Character();
}
...
if (characters != NULL)
{
for(int i = 0; i < MAX_CHARACTERS; ++i)
{
delete characters[i];
}
delete [] characters;
}
A better solution is the standard vector class:
#include <vector>
...
const int MAX_CHARACTERS = 11;
std::vector<Character> characters;
for (int i = 0; i < MAX_CHARACTERS; ++i)
{
characters.push_back(Character());
}
...
characters.clear();
Notice how much easier the cleanup was? (And in this case, it's optional, since when characters is destroyed it will automatically call the destructor of each item it contains.)
Also:
Character *characters[11];
should be
Character *characters[12];
and
for(i=11;i<=0;i--)
should be
for(i=11;i>=0;i--)
i realize this is a simplified use and all, but why bother with heap access at all?
just using
Character characters[11];
could be just as valid, and safe.
std::vector<> is nice, but if the list is always fixed size, and there's no heap involved in member data, why not?