codeblocks c++ stops working may be due to referencing - c++

//in header file(in User class):
int howManyOpponents =0;
User** userArray; //(which is initialized to userArray = new User*[5] in the constructor)
//in class file:
void User::addWin(User* aUser)
{
userArray[howManyOpponents] =aUser;
howManyOpponents++;
}
//in main file
int maximumUser = 20;
User* userList[maximumUser];
(*userList[i]).addWin(userList[j]);
codeclocks stops working, I've traced the problem to the User::addWin and tried many different referencing or pointing settings but couldn't handle it. There may be a simple bug.
Thank you.

User* userList[maximumUser];
Creates an array of maximumUser User pointers. No actual instances of User are constructed.
You then try to call a method with one of these uninitialised pointers, causing the crash:
(*userList[i]).addWin(userList[j]);
To fix, create an array of actual User instances (assuming User's constructor does not require arguments):
User userList[maximumUser];
userList[i].addWin(userList[j]);

Consider passing argument by reference instead of passing them by pointers. Try to avoid using raw poiters in your code. If you really need pointers, think about using smart pointers.

Here's a example about how to use arrays of pointers:
size_t maxUsers = 5;
size_t maxUserLen = 48;
char** UserList = 0;
// First, allocates a array of pointers
UserList = new char*[maxUsers];
// Second, allocates each pointers in the array of pointers
for(size_t i=0; i<maxUsers; i++)
{
UserList[i] = new char[maxUserLen];
memset(UserList[i], 0, maxUserLen);
}
// Add user
const char* user1 = "Mike";
const char* user2 = "James";
strcpy(UserList[0], user1); // First element in the list
strcpy(UserList[1], user2); // Second element in the list, etc...

Related

C++ - Creating pointers to elements of an array containing pointers to class objects

I'm new to C++ and programming in general and am trying to learn by creating a sort of game as I go along. I can't find any information on how to achieve what I need to do.
I have created the following code, which I believe creates new objects of class Player off the heap, and creates pointers to these objects in an array.
int playerObjects(int n, int gameMode)
{
Player* playerArray = new Player[n];
for (int i = 0; i < n; i++)
{
playerArray[i].balance = 50;
playerArray[i].score = 0;
playerArray[i].playerNum = (i+1);
int m = (i+1);
playerArray[i].playerName = playerArray[i].playerN(m);
string playerNam = playerArray[i].playerName;
playerArray[i].playerAge = playerArray[i].playerA(playerNam);
playerArray[i].teamNum = 0;
}
}
where n is the number of players (from 1-4).
The class Player I have created myself:
What I now want to do is return to the calling function, main(), and still be able to access and modify these objects. I cannot figure out how. I have attempted to create pointers to each element of the array, like so:
Player** pOne = playerArray[0];
Player** pTwo = playerArray[1];
Player** pThree = playerArray[2];
player** pFour = playerArray[3];
which I think declares pOne to be a pointer to a pointer to an object of class Player (the array element), however, this throws the error:
cannot convert 'Player' to 'Player**' in initialization
doing it like this throws the same error, but in assignment rather than initialization (obviously):
Player** pOne;
pOne = playerArray[0];
How do I do it?
And, once I have done it, how do I then pass this from main() to other functions that also need to have access to these?
Would it be better to declare the array globally?
Thanks
The easiest way is probably to just return the pointer.
Player* playerObjects(int n, int gameMode)
{
Player* playerArray = new Player[n];
...
return playerArray;
}
Alternatively if you want to keep the return value as an int, you can pass a pointer to a pointer to the function. You can then create the array in the specified pointer.
int playerObjects(int n, int gameMode, Player** playerArray)
{
*playerArray = new Player[n];
for (int i = 0; i < n; i++)
{
*playerArray[i].balance = 50;
*playerArray[i].score = 0;
...
}
}
You can call this function by doing:
Player* playerArray;
playerObjects(n, gameMode, &playerArray)
And then access the items of playerArray as usual:
playerArray[0].xyz;
Don't forget that after you've allocated memory with with new[], you need to delete it with delete[] when you're finished with it.
The function musts to return (either as the return value or as a referenced parameter) the pointer to the first element of the created array. Thus in main you can use the pointer with the subscript operator.
Or more better approach is to use standard container std::vector<Player> and return it from the function.
playerArray[0] will return object of type Player, so typecast operation you are doing is incorrect.
If you want to use this array in main() then you can return playerArray from function playerObjects().

Cannot operate on an array of structures which comprise a string C++

I have a structure which includes a string field. I create an array of those structures and then I want to pass them to a function (by reference). Everything works perfectly fine when I comment out the string field, but if I don't the program crashes. I can't find an answer to this anywhere..
Here's the code (I reduced it to only show the issue):
struct student {
int a;
int b;
string name[20];
char status;
};
void operation(student the_arr[1],int number_of_students) {
delete[] the_arr;
the_arr = new student[3];
for(int i = 0; i<3; i++) {
the_arr[i].a = i+5;
the_arr[i].b = i+4;
}
}
int main() {
student *abc;
abc = new student[0];
operation(abc, 0);
system("pause");
return 0;
}
I need the array to be dynamic so I can change its' size when I need to.
Assuming you can't use std::vector instead of dynamically allocated arrays follow the answer below. In any other case you should use the containers provided by the standard library.
Note: Your program doesn't crash. The only things the compiler will complain about it the allocating zero elements part, but will let you compile and run this program.
Your function is completely wrong. When using dynamic allocation you can simply pass a pointer like this:
void operation(student* the_arr, int number_of_students) {
Then inside your function you are dynamically allocating memory which is stored inside the the_arr pointer which is not passed by reference therefore leading to the creation of a local pointer variable that will lose the pointer after its execution:
void operation(student*& the_arr [...]
I suggest you to avoid the below solution though and return the new pointer instead:
student* operation(student* the_arr, int number_of_students) {
delete[] the_arr;
the_arr = new student[3];
[...]
return the_arr; // <----
}
Allocating abc = new student[0]; doesn't make any sense. You are trying to allocate an array of 0 elements. Maybe you meant abc = new student[1];?
You should just use the vector or other sequence objects. Though I'm not sure what you are trying to do with your code. Here's a quick example:
// Vector represent a sequence which can change in size
vector<Student*> students;
// Create your student, I just filled in a bunch of crap for the
// sake of creating an example
Student * newStudent = new Student;
newStudent->a = 1;
newStudent->b = 2;
newStudent->name = "Guy McWhoever";
newStudent->status = 'A';
// and I pushed the student onto the vector
students.push_back( newStudent );
students.push_back( newStudent );
students.push_back( newStudent );
students.push_back( newStudent );

Pointer and Array problem

In C++, I'm having trouble with pointers etc. How can I fix the following problem?
error: no match for 'operator=' in '(stage->Stage::tiles + ((unsigned int)(((unsigned int)t) * 12u))) = (operator new(12u), (, ((Tile*))))'|
note: candidates are: Tile& Tile::operator=(const Tile&)|*
stage.h
#include "Tile.h"
class Stage {
public:
Tile *tiles;
int size;
void init(int size);
};
stage.cpp
void Stage::init(int size) {
this->size = size;
this->tiles = new Tile[size];
}
application.cpp
#include "Stage.h"
#include "Tile.h"
bool setTiles( Stage * stage ) {
for( int t = 0; t < stage->size; t++ ) {
stage->tiles[t] = new Tile();
}
return true;
}
stage.init(1234);
setTiles( &stage );
Also, I don't really know when to use object.attribute and when to use object->attribute?
stage->tiles[t] = new Tile();
You're calling new on something that's not a pointer. True, tiles is a pointer to an array, however, each element of that array is NOT a pointer. In order for that work, you would need an array of pointers, or a pointer to a pointer ,such as:
Tile **tiles;
What you could also do is create a separate pointer object, allocate it, and then copy the data to your array element by using
stage->tiles[i] = *somePointer;
and then deleting the pointer afterwards to free that allocated memory. This will preserve the copy because you invoked the copy constructor.
You are trying to allocate a pointer with a pointer to an array. Try this one:
class Stage {
public:
Tile **tiles;
void init(int size);
};
stage->tiles[t] = new Tile();
The above is not a valid C++ code, which you are perhaps confusing with the way new is used in other language such as C#. Though new can be used to allocate dynamic memories, but assigning an object to a particular element in the dynamically created array doesn't need the new construct. In fact, the object is already created as soon as you called new Tile[size]. What you may want to do is, create an object of type Tile and assign it to a particular element in tiles.
Tile myTile;
// do something with myTile
this->tiles[0] = myTile;
new Tiles() returns a pointer to a Tiles instance.
Tile *tiles defines an array out Tiles, not pointers.
Start with Tile **tiles instead.

STL List copies a struct, but the copied values are offset by two memory addresses

I'm compiling using Code::Blocks on Windows 7 using the MinGW compiler (which I can only assume is the latest version; both Code::Blocks and MinGW were installed this past week). My issue crops up under a particular circumstance, and my attempts to write a simpler script that demonstrates the problem have failed (which implies that there is something wrong with my structure). Also, my apologies for how long this post is.
Currently, I'm rolling with one class, FXSDL, which will act as an SDL wrapper:
class FXSDL
{
public:
FXSDL();
virtual ~FXSDL();
int Initialize();
int Render();
FXID CreateCharacter(FXID hRefID, string fpImage, int wpxTile, int hpxTile, map<int, vector<int> > htAnims);
int SetAnim(FXID hRefID, FXID hAnimID);
FXID hPlayer;
protected:
private:
list<FXSurface> m_lstFXObjects;
list<FXSurface>::iterator m_liFirst;
SDL_Surface* m_lpsfSDLScreen;
Uint32 m_tmOld;
Uint32 m_tmFrame;
};
The value type of my list is:
struct FXSurface
{
FXID hRefID;
int wpxTile;
int hpxTile;
int wpxTotal;
int hpxTotal;
int cntTiles;
map<int, vector<int> > htAnims; // All animations
map<int, vector<int> >::iterator vCurr; // Currently active animation
vector<int>::iterator fiCurr; // Currently active frame
SDL_Surface* lpsfSDL;
SDL_Rect* lprcTiles; // Predefined frame positions
string* fpImage;
};
I've implemented very simple initialize and render function. The CreateCharacter function takes a few parameters, the most important of which is htAnims, a map of integer vectors (idea being: I define numeric ids with easy-to-remember representations, such as FXA_IDLE or FXA_WALK, as the key, and the series of number values representing frames for the animation as a vector). This could be fairly easily implemented as a multidimensional integer array, but animations are variable in length and I want to be able to add new anims (or redefine existing ones) without having to recast an array.
The CreateCharacter function is simple. It creates a new FXSurface, populates it with the required data, and pushes the new FXSurface onto the list:
FXID FXSDL::CreateCharacter(FXID hRefID, string fpImage, int wpxTile, int hpxTile, map<int, vector<int> > htAnims)
{
//list<FXSurface>::iterator lpsfTemp;
FXSurface lpsfTemp;
list<FXSurface>::iterator lpsfPos;
SDL_Rect* lprcCurr = NULL;
int cntTileW = 0;
int cntTileH = 0;
int cntCurr = 0;
// Start off by initializing our container struct
//lpsfTemp = new FXSurface();
lpsfTemp.lpsfSDL = IMG_Load(fpImage.c_str()); // Try to load the requested image
if(lpsfTemp.lpsfSDL != NULL) // If we didn't fail to
{
// Assign some variables for tracking
lpsfTemp.hRefID = hRefID;
lpsfTemp.fpImage = &fpImage;
lpsfTemp.wpxTotal = lpsfTemp.lpsfSDL->w;
lpsfTemp.hpxTotal = lpsfTemp.lpsfSDL->h;
// If a tile width was specified, use it
if(wpxTile != 0)
{
lpsfTemp.wpxTile = wpxTile;
lpsfTemp.hpxTile = hpxTile;
} // Otherwise, assume one tile
else
{
lpsfTemp.wpxTile = lpsfTemp.wpxTotal;
lpsfTemp.hpxTile = lpsfTemp.hpxTotal;
}
// Determine the tiles per row and column for later
cntTileW = lpsfTemp.wpxTotal / lpsfTemp.wpxTile;
cntTileH = lpsfTemp.hpxTotal / lpsfTemp.hpxTile;
// And the total number of tiles
lpsfTemp.cntTiles = cntTileW * cntTileH;
lpsfTemp.lprcTiles = new SDL_Rect[cntTileW*cntTileH];
// So we don't calculate this every time, determine each frame's coordinates and store them
for(int h = 0; h < cntTileH; h++)
{
for(int w = 0; w < cntTileW; w++)
{
cntCurr = (h*cntTileW)+w;
lprcCurr = new SDL_Rect;
lprcCurr->w = lpsfTemp.wpxTile;
lprcCurr->h = lpsfTemp.hpxTile;
lprcCurr->x = w*lpsfTemp.wpxTile;
lprcCurr->y = h*lpsfTemp.hpxTile;
lpsfTemp.lprcTiles[cntCurr] = *lprcCurr;
lprcCurr = NULL;
}
}
// Now acquire our list of animations and set the default
//lpsfTemp.htAnims = new map<int, vector<int> >(*htAnims);
lpsfTemp.htAnims = htAnims;
lpsfTemp.vCurr = lpsfTemp.htAnims.find(FXA_WALK_EAST);
lpsfTemp.fiCurr = lpsfTemp.vCurr->second.begin();
this->m_lstFXObjects.push_back(lpsfTemp);
}
else
{
hRefID = 0;
}
return hRefID;
}
It is precisely as the object is pushed that the error occurs. I've stepped through the code numerous times. Initially, I was only able to tell that my iterators were unable to dereference to the FXSurface object. After using watches to identify the exact memory address that the iterator and list objects pointed to, and dereferencing the address, I noticed the reason for my segfaults: all the values which I put into the original FXSurface were pushed down two memory blocks when the list object copied it!
My process for doing this is simple. I set up a breakpoint at the return statement for CreateCharacter, which gives me a view of lpsfTemp (the FXSurface I later add to the list) and m_lstFXObjects (the list I add it to). I scroll through the members of m_lstFXObjects, which brings me to _M_node, which contains the memory address of the only object I have added so far. I add a watch to this address in the form of (FXSurface)-hex address here-
First, find the address:
(There should be a picture here showing the highlighted _M_node attribute containing the list item's address, but I can't post pictures, and I can only post one URL. The second one is by far more important. It's located at http://www.fauxsoup.net/so/address.jpg)
Next, we cast and deference the address. This image shows both lpsfTemp and the copy in m_lstFXObjects; notice the discrepancy?
http://www.fauxsoup.net/so/dereferenced.jpg - See? All the values are in the correct order, just offset by two listings
I had initially been storing fpImages as a char*, so I thought that may have been throwing things off, but now it's just a pointer and the problem persists. Perhaps this is due to the map<int, vector<int> > I store?
FXSDL has a destructor, but no copy constructor and no assignment operator. Yo you're using naked pointers, but violate the Rule of Three.
I'm not going to look any further.
Use smart pointers to manage resources. Do not put a naked resource into a type, except when that type's only intention is to manage this one resource. From another answer given yesterday:
As a rule of thumb: If you have to manually manage resources, wrap each into its own object.
At a glance, I'd say you're double-deleting lpsfSDL and/or lprcTiles. When you have raw pointers in your structure, you need to follow the rule-of-three (implement copy constructor, assignment operator, and destructor) to properly manage the memory.
These lines look wrong to me:
lprcCurr = new SDL_Rect;
lprcCurr->w = lpsfTemp.wpxTile;
lprcCurr->h = lpsfTemp.hpxTile;
lprcCurr->x = w*lpsfTemp.wpxTile;
lprcCurr->y = h*lpsfTemp.hpxTile;
lpsfTemp.lprcTiles[cntCurr] = *lprcCurr;
lprcCurr = NULL;
lpsfTemp.lprcTiles is a SDL_Rect*. lprcTemp.lprcTiles[cntCurr] is a SDL_Rect. You should be writing this, IMHO:
SDL_Rect tmpRect;
tmpRect.w = lpsfTemp.wpxTile;
tmpRect.h = lpsfTemp.hpxTile;
tmpRect.x = w*lpsfTemp.wpxTile;
tmpRect.y = h*lpsfTemp.hpxTile;
lpsfTemp.lprcTiles[cntCurr] = tmpRect;
Dump the lprcCurr entirely.
Now this code:
lpsfTemp.vCurr = lpsfTemp.htAnims.find(FXA_WALK_EAST);
lpsfTemp.fiCurr = lpsfTemp.vCurr->second.begin();
This is bad. These iterators are invalid as soon as the push_back completes. That push_back is making a copy of lpsfTemp. The map and vector members are going to copy themselves and those iterators will copy themselves but they will be pointing to lpsfTemp's members which are going to be destroyed as soon as CreateCharacter exits.
One way to fix that would be to push_back a FXSurface object at the beginning, use back() to get its reference and operate on that instead of lpsfTemp. Then the iterators would stay consistent and they should stay consistent since you are using a list which does not copy its objects around. If you were using a vector or deque or anything other than a list you would need to manage all those pointers and iterators in the copy constructor and assignment operator.
Another thing: Double and triple check your array bounds when you access that lprcTiles array. Any mistake there and you could be scribbling over who knows what.
I don't know if any of that will help you.

std::vector overwriting final value, rather than growing?

I'm having an issue where using vector.push_back(value) is overwriting the final value, rather than appending to the end. Why might this happen? I have a sample item in the vector, so it's size never hits zero. Below is the code..
void UpdateTable(vector<MyStruct> *Individuals, MyStruct entry)
{
MyStruct someEntry;
bool isNewEntry = true;
for (int i = 0; i < Individuals->size(); i++)
{
if (!(strcmp(Individuals->at(i).sourceAddress, entry.sourceAddress)))
{
isNewEntry = false;
//snip. some work done here.
}
}
if(isNewEntry)
{
Individuals->push_back(entry);
}
}
This let's my first "sample" value stay in, and will allow for just one more item in the vector. When 2 new entries are added, the second overwrites the first, so the size is never larger than 2.
edit: More code, since this is apparently not the issue?
void *TableManagement(void *arg)
{
//NDP table to store discovered devices.
//Filled with a row of sample data.
vector<MyStruct> discoveryTable;
MyStruct sample;
sample.sourceAddress = "Sample";
sample.lastSeen = -1;
sample.beaconReceived = 1;
discoveryTable.push_back(sample);
srand(time(NULL));
while(1)
{
int sleepTime = rand() % 3;
sleep(sleepTime);
MyStruct newDiscovery = ReceivedValue();
if (newDiscovery.lastSeen != -1000) //no new value from receivedValue()
{
UpdateTable(&discoveryTable, newDiscovery);
}
printTable(&discoveryTable);
}
return NULL;
}
I'm going to hazard a guess:
Suppose MyStruct is declared like
struct MyStruct
{
const char *sourceAddress;
// Other Gubbins ...
};
And that ReceivedValue does something like
MyStruct ReceivedValue()
{
static char nameBuffer[MAX_NAME_LEN];
// Do some work to get the value, put the name in the buffer
MyStruct s;
s.sourceAddress = nameBuffer;
// Fill out the rest of MyStruct
return s;
}
Now, every structure you push into your vector has sourceAddress pointing to the same global buffer, every time you call ReceivedValue it overwrites that buffer with the new string - so every entry in your vector ends up with the same string.
I can't be sure without seeing the rest of your code, but I can be sure that if you follow some of the good C++ style suggestions in the comments to your question this possiblity would go away.
Edit for clarification: there's no need to heap allocate your structures, simply declaring sourceAddress as a std::string would be sufficient to eliminate this possibility.
The scope for the items you are pushing into the database is expiring. They're being destructed when you leave the {} in which they were created - and as such the reference to them is no longer valid.
You need to change it from vector<MyStruct> to vector<MyStruct*> (preferably using safe pointers from Boost:: instead of pointers, but you get the idea).
You are creating the item within the (limited) scope and pushing it onto the vector (while the struct is copied, the strings in it are not!) it then reuses the same memory location (most likely if properly optimized) to store the next "new" struct and the one after that and so on and so forth.
Instead, within the limited scope create MyStruct *myObject = new MyStruct and assign its values, then push the pointer to the vector.
Remember to delete all values from the vector before clearing it/destroying it!!
Or, of course, you could use std::string/CString/whatever instead of a char array and avoid the issue entirely by having a safe-to-copy struct.
ComputerGuru's answer works however there in another alternative. You can create a copy constructor and overload operator= for MyStruct. In these operations, you need to copy the actual string into the new struct. In C++, structs are nothing more than classes with default public access instead of default private access. Another alternative is to use std::string instead of char* for the string value. C++ strings already have this behavior.
struct MyStruct {
std::string sourceAddress;
int lastSeen;
int beaconReceived;
};
Seems odd to me: Maybe there is something wrong with the //snip part of the code?
Try to log the size of the vector before and after the push_back call (either in the debugger or using cout) and also have a look at the isNewEntry variable.
Your code looks alright to me. Is it possible that you are not passing the right vector in? What I mean is that the behaviour you describe would appear if somehow your Individuals vector is being reset to its orginal 1-entry state before you tried to add the 3rd entry, then it would appear as if your 2nd entry was being overwritten.
Here is what I mean:
int test_table()
{
string SampleAddresses[] = {"Sample Address 1", "Sample Address 2"};
for (int i = 0; i < 2; i++)
{
// All this work to build the table *should* be done outside the loop; but we've accidentally put it inside
// So the 2nd time around we will destroy all the work we did the 1st time
vector<MyStruct> Individuals;
MyStruct Sample;
Sample.sourceAddress = "Sample Address 0";
Test.push_back(Sample);
// this is all we meant to have in the loop
MyStruct NewEntry;
NewEntry.sourceAddress = SampleAddresses[i];
UpdateTable(Individuals, NewEntry);
}
//Now the table has 2 entries - Sample Address 0 and Sample Address 2.
}
If this was all your code then the problem would be obvious. But it might be concealed in some other pieces of code.