A class array inside of a class - issues with dynamic arrays (c++) - c++

My homework is that I have to make a class (register) which contains 3 class arrays (birds, mammals, reptiles) which are in the animal class. Animal is the friend of Register. I will only show the birds part, to keep it simple.
The register class looks like:
class Register
{
Bird* birds;
unsigned int birdSize;
public:
...
}
The constructor of register:
Register::Register()
{
this->birds = new Bird[0];
this->birdSize = NULL;
}
Now I have a function in register that adds one element to the birds array, the input is cin.
void Register::add()
{
...
if (birdSize == 0)
{
birds = new Bird[0];
Bird* temp = new Bird[0];
temp[0].add();
this->birds = temp;
birdSize++;
}
else
{
Bird* temp = new Bird[birdSize+1];
for (unsigned int i=0; i<=birdSize; i++)
{
temp[i] = this->birds[i];
}
temp[birdSize+1].add();
birds = new Bird[birdSize+1];
birds = temp;
birdSize++;
}
temp[0].add() has the cin, it works properly. When I run the program, the user has to add 2 birds to the array. The problem occurs when reaching the part under 'else', so the second element of the array. The program surely reaches "temp[birdSize+1].add();" while running, then the "xyz.exe has stopped working" window pops up and it says in the details " Fault Module Name: StackHash_7e8e" so I'm sure something is wrong with the memory allocation, but the problem is that when I try to find the problematic line in debug mode, everything works fine.
Well, not everything. The program has a print() function, it prints out everything in Register. The second element of the array is the same as the first.
I have no clue what to do. I read many forum posts, read a cpp book, watched online tutorials, but I can't find the solution for this problem. Please help.

Array index starts from 0. So in else part you are writing
Bird* temp = new Bird[birdSize+1]; // size =birdSize +1;
So valid index range will be 0 -> birdSize, not birdSize+1.
The problem is
temp[birdSize+1].add();
you are using birdSize+1th index. It should be
temp[birdSize].add();
There are other bugs in your code:
for (unsigned int i=0; i<=birdSize; i++) // should be i<birdSize
{
temp[i] = this->birds[i];
}
There are other bad coding in your program:
Register::Register()
{
this->birds = new Bird[0]; // should be this->birds=NULL
this->birdSize = NULL; // should be this->birdSize = 0
}
And obviously if your homework does not demand it, you should not use arrays in this way. For variable size container, use vector, list.... Array is only when the size is fixed.

Related

Segmentation Fault when utilizing struct array dereference

I'm working on a school assignment. It is an assignment in which every 2 weeks, we have to either expand or change the layout of it. This week, we are forced to use pointers. I'm having a hard time understanding memory and how to allocate it properly without having segmentation faults.
I've created a struct array which is initialized to a char pointer. Every time i loop, after the 1st loop i get "segmentation faults". I simply don't understand why?
I could include the whole code but according to gdb my issue is pertaining to 1 specific line.
const int arraySize = 100;
int counter = 0;
struct contacts{
char * name;
char * date;
char * note;
};
contacts * contactList[arraySize] =
contactList = new contacts;
for(int i = 0; i <= counter; i++){
contactList[i]->name = new char[20]; //Segmentation Fault here
std::cout << contactList[i]->name << std::endl;
//first 1 outputs = fine
//2nd output = segmentation error
counter++;
}
The code is simplified and minimilized for easy reading. If anyone wants it i can insert the whole code. Just be wary that is relatively big. I have set breakpoint through my code to narrow it down. It has come down to that specific statement. Everything else i perfectly fine, especially since it all compiles perfectly fine.
Any hints or assistance with it can be great.
Also I'm not allowed to use any vectors, strings, etc., only cstrings.
User mentioned that i only create 1 contact.
contacts * contactList[arraySize];
contactList = new contacts;
//Instead it should be like this:
contacts * contactList[arraySize];
contactList = new contacts[arraySize];
Update:
I've tried using what everyone recommended.
contacts* contactList[arraySize];
contactList = new contacts[arraySize];
But i get this error:
error: incompatible types in assignment of‘ContactClass::contacts*’ to ‘ContactClass::contacts* [100]’
Your first problem is in this line:
contacts * contactList[arraySize] = new contacts;
it should be
contacts* contactList = new contacts[arraySize];
next problem is here
for(int i = 0; i <= counter; i++){
should be
for(int i = 0; i < arraysize; i++){
contactList[i].name = new char[20];
}

How do I declare a dynamic array of structs that contain a Queue member?

This is from a homework assignment that was already turned in. The program is a card game that plays correctly but seg faults when the game is over. I can trace the core dump to my delete [] playerArr, but I think the real problem is in how I'm declaring my playerArr.
I have a constructor, copy, overloaded operator and destructor in my .h file that works well with other programs so I think my problem is in main. I've looked at several other questions here and on google and haven't found one quite like this. Here are the code snippets:
struct Player
{
int currentHand; //current number of cards in given player's hand
Queue hand; //queue to store player's hand
};
in main I allocate an array of structs, I think this is my problem. I've trial and errored a variety of approaches but this one allows my program to compile and my game to play as designed:
//allocate array of Player structs
Player *playerArr = new Player[numPlayers];
for (int i = 1; i <= numPlayers; i++)
playerArr[i].currentHand = 0;
//enqueue playerArr.hand
deal(playerArr, deck, numPlayers, currentDeck);
this is the sequence I use to clean up before deleting, the core dumps after cout:
//exit do-while loop and end game
}
while (playerArr[currentPlayer - 1].currentHand != 0);
for (int i = 1; i < numPlayers; i++)
{
while (playerArr[i].currentHand > 0)
{
playerArr[i].hand.dequeue(catchQ);
playerArr[i].currentHand--;
}
}
//empty all deck/discard stacks
while (!deck.isEmpty())
deck.pop(catchPop);
while (!discard.isEmpty())
discard.pop(catchPop);
//reset hand/deck counters to defaults
catchQ = 0;
catchPop = 0;
currentDeck = 52;
currentPlayer = 1;
numPlayers = 2;
cout << "\n\n\n\t Good Game!" << endl << endl;
//free dynamic memory
delete [] playerArr;
It's too late for me to change my grade on this program and with finals week I don't have time to visit my prof during office hours so if someone has a solution for me I can learn from this mistake and move on.
Thank you
One probable cause of the problem is that you forget that array-indexes are zero-based.
An array of numPlayers elements will have indexes from 0 to numPlayers - 1 (inclusive).
The first loop you show doesn't use that, instead if goes from 1 to numPlayers, leading you to index the allocated memory out of bounds which leads to undefined behavior.

Building a dynamically allocated array of class Objects

First off, if this problem seems incredibly easy to you, I want to in advance apologize but I am only a beginner.
I have been stuck now for about a week with this problem and it is getting ridiculous since it shouldn't be that hard, even for a complete beginner like me.
I am writing a program which reads a bunch of information regarding receipts from a text file, like name, sum, date etc. and then prints it out to the screen. Simple enough, right? Well I started with using static arrays in my two classes Transaction and TransactionsList and it was working fine, I was printing the contents of the file to the screen just fine one line after the other.
Now I need to do this using dynamic arrays.
Each line in the text file contains a date, type, name, sum, number of friends and name of those friends which should be read an stored as a Transaction class object inside the dynamic array trans. This is what I am having trouble understanding no matter how much theory and googling I do on the subject. Where should I use an overloaded assigment operator, where a copy constructor and how do I call them properly? I have read up on these concepts but I can't use them in my program still. These are questions just flying around in my head right now.
I have changed the arrays friends and trans to be declared as pointers which I understand is correct. I then want to allocate memory for the arrays with "new", but here I am starting to get unsure just where I allocate with new, inside the contructors of their classes or inside the functions where they are needed?
I realize vectors is the answer to alot of these problems but I should tell you that I have not gotten into vectors yet, so I am trying to solve this problem without vectors. I realize this may be be a bit backwards, but I should be able to build my dynamically allocated array of objects and print it out without vectors I think. I have heard they are more practical but for now I have to understand this assignment without the concept of vectors.
I have read up on difference between shallow copies and deep copies as well and I get the theory, but I just can't implement it somehow. (I am probably retarded I know).
This is what I have got so far:
#include <iostream>
#include <string>
#include <fstream>
#include <cstdlib>
#include <iomanip>
using namespace std;
class Transaction
{
private:
string date;
string type;
string name;
double sum;
int nr_friends;
string *friends;
public:
Transaction();
~Transaction();
Transaction &operator = ( const Transaction &t );
string get_name();
int get_no_friends();
double get_sum();
bool readOneTrans( istream &is );
void writeOneTrans( ostream &os );
};
class TransactionsList
{
private:
Transaction *trans;
int no_Trans;
public:
TransactionsList();
~TransactionsList();
void read( istream & is );
void print( ostream & os );
void add( Transaction & t );
};
int main()
{
ifstream inFile("test.txt");
Transaction t;
TransactionsList tl;
// t.readOneTrans(inFile); // reading just one line works fine (when uncommented)
// t.writeOneTrans(cout); // printing works too just fine
//tl.read(inFile); // here I want to read all contents of file
//tl.print(cout); // and here print out them to the screen
return 0;
}
Transaction::Transaction()
{
date = "000000";
type = "transp";
name = "default";
sum = 0.0;
nr_friends = 0;
friends = NULL;
}
Transaction::~Transaction()
{
delete [] friends;
}
Transaction &Transaction::operator = ( const Transaction &t )
{
if ( this != &t )
{
delete[] friends;
date = t.date;
type = t.type;
name = t.name;
sum = t.sum;
nr_friends = t.nr_friends;
friends = new string[nr_friends];
for ( int i = 0; i < nr_friends; i++ )
{
friends[i] = t.friends[i];
}
}
return *this;
}
string Transaction::get_name()
{
return name;
}
double Transaction::get_sum()
{
return sum;
}
int Transaction::get_no_friends()
{
return nr_friends;
}
bool Transaction::readOneTrans( istream &is )
{
is >> date >> type >> name >> sum >> nr_friends;
friends = new string[nr_friends];
for (int i = 0; i < nr_friends; i++)
{
is >> friends[i];
}
return is;
return !is.eof();
}
void Transaction::writeOneTrans( ostream &os )
{
os << left << setw(10) << date <<
setw(10) << type << setw(10) << name
<< setw(10) << sum << setw(10)
<< nr_friends;
for (int i = 0; i < nr_friends; i++)
{
os << left << setw(8) << friends[i];
}
os << endl;
}
TransactionsList::TransactionsList()
{
no_Trans = 1;
trans = new Transaction[no_Trans];
}
TransactionsList::~TransactionsList()
{
delete [] trans;
}
void TransactionsList::read( istream & is )
{
Transaction t;
while ( t.readOneTrans( is ))
{
add( t );
}
}
void TransactionsList::print( ostream & os )
{
Transaction t;
for (int i = 0; i < no_Trans; i++)
{
t = trans[i];
t.writeOneTrans( os );
}
if (os == cout)
{
os << "\nNumber of transactions: " << no_Trans << endl;
}
}
void TransactionsList::add( Transaction & t )
{
// each time I read a line from the file it is passed in as object t here
// here I want to add this object t to the dynamic array trans somehow
// and keep building the array with a new class object every time
// Probably by overloading assignment operator somehow but how?
trans[no_Trans] = t;
no_Trans++;
// i have no idea what to put here to make it work...
}
So as you can see, what I want to do is continually build up the dynamic array trans with different objects of the class Transaction, each instance representing a different line in the text file I am reading from so that I can print out all the lines in the file to the screen in the end.
The output lines should look like this:
011216 food John 300 2 Nathan Julia
To do this now dynamically, I realize I must copy the contents of object t that is passed in in the method "add" and add it to the array trans and somehow without losing the data of the earlier t:s which are representing the previous text lines. This was easy for me to do while the arrays where static ones, as I just assigned the next element in the array trans to be equal to the current object t (inside the add function). This is how my add function looked with static arrays:
void TransactionsList::add( Transaction & t )
{
trans[no_Trans] = t;
no_Trans++;
}
Obviously this doesn't work when you are working with dynamically allocated memory. I read some theory on this and I understand one cannot change the size of the array while it is running so the array actually has to be deleted and then allocated as a larger array and copy over the old contents using a deep copy, which doesn't just copy the memory address for the dynamic array but makes a new array with the olds content.
As you can see, I have read alot of theory but don't really understand it...
Can anyone help? I would be immensely thankful as I have not learned anything in a week and this is really killing me right now. I need to make progress now!
Some hints about the container:
Don't use using namespace std; (why?)
An unsigned integral size in c++ is usually represented as std::size_t from <cstddef>.
Get familiar with rule of three / rule of three/four/five.
A quite useful idiom that is usually applied to such classes is: 'Resource Acquisition Is Initialization (RAII)'.
Bottom line:
When managing resources we usually need to have
a destructor
a copy constructor
a move constructor
a copy assignment operator
a move assignment operator
Resource aquisition should only happen in the constructor.
Functions such as add should not perform seperate resource acquisition but create a temporary of appropriate size and swap/move contents.
The issue of constructing a dynamically-allocated array is completely separate from the issue of constructing the objects themselves.
class TransactionList {
Transaction *trans;
size_t trans_size;
size_t no_Trans;
public:
TransactionList(size_t initial_size)
: trans(new Transaction[initial_size]),
trans_size(initial_size),
no_Trans(0)
{
}
~TransactionList()
{
delete[] trans;
}
// ...
};
That's it. There's nothing different about your existing add() method. It still works exactly the same way, because of the fact that an array is really just a pointer to the first element in the array, which is still the case here.
But you do need to figure out what to do when no_Trans reaches the actual allocated trans_size. That's going to be your homework assignment.
What you probably want to do, though, is to change this to an array of Transaction * objects, and also dynamically allocate each Transaction when it's added to the array. That will require additional work.
(This answer requires no extra knowledge, and needs only a little bit change of your code)
Things get weird in the constructor:
no_Trans = 1;
trans = new Transaction[no_Trans];
People usually leave some space for future elements to add:
max_Trans = 100;
no_Trans = 0;
trans = new Transaction[max_Trans];
And in add()
if (no_Trans >= max_Trans) { // no more space?
// make a new array that is as twice big as the old one
max_Trans = 2 * max_Trans;
Transaction new_trans = new Transaction[max_Trans];
// copy elements to the new array
for (int i = 0; i < no_Trans; i++)
new_trans[i] = trans[i];
// delete the old one and start to use the new one
delete[] trans;
trans = new_trans;
}
trans[no_Trans] = t;
no_Trans++;
Of course max_Trans can also be 1, and make it grow as 1, 2, 3, 4... But that requires new on each add operation, which is inefficient.

I am stuck with copying a class given an address, I am segfaulting

I have struggled with it for a while but I really can't get it, I am just getting segfaults. I am trying to copy a class, the function I am writing to copy is also below. Crossed out are combinations that I have tried in vain, it's time to call for help
class Scene
{ private:
int max;
int* x_row, *y_col; // maximum and min coordinates of each image
Image**image_layers;
}
void Scene::_copy(const Scene &source)
{
max = source.max;
x_row = new int[source.x_row];
y_col = new int[source.y_col];
image_layers = new Image*[source.max];
for(int i = 0; i < source.max; i++)
{
if(source.image_layers[i] != NULL)
{
//image_layers[i] = new Image(*(source.image_layers[i]));
// image_layers[i] = new Image;
//*image_layers[i] = *source.image_layers[i];
// image_layers[i] = source.image_layers[i];
}
else
{
image_layers[i] = NULL;
}
x_row[i] = source.x_row[i];
y_col[i] = source.y_col[i];
}
EDIT:
I forgot to say that this function is called as " scene(*set) "
The segfault happens here or because of this:
x_row = new int[source.x_row];
y_col = new int[source.y_col];
On the right hand side, you use the address source.x_row as an array size. This is a very large number that most likely will cause the allocation to fail.
You need to keep a member for holding the size or better yet use a std::vector<int> object instead.
Copying C arrays are done faster with memcpy. With C++ vectors, you can just assign one to the other:
x_row = source.x_row
Nothing to do with the question, but this function should be named operator=, will make using the class easier by assigning one instance to another:
Scene & Scene::operator=(const Scene &source)
{
// copy elements
...
return *this;
}
x_row = new int[source.x_row];
y_col = new int[source.y_col];
Are you sure about above code?
source.x_row is pointer

I think I am messing up the scope of these pointers, C++?

So this is a reduced version of my main / Initializer function. When I call it and it has to add any items to the players inventor, I get a Debug Assertation Failed error.
It seems to me like I am mixing up the scope somewhat?
Am I declaring something new inside the scope of the function, and then not being able to access it again out in main?
I tried a few things inside the function, like using Getters/Setters instead of assigning is completely, like p_player = p but I don't think that actually deals with the problem at all, and I'm kind of confused.
int main()
{
Array<Item> items(3);
string itemsfilename = "itemsfile.txt";
Initializer::InitializeItems(items, itemsfilename);
Login login;
Player p1;
string filename = login.LoginToGame();
Initializer::InitializePlayer(p1, rooms, items, 3, filename);
}
void Initializer::InitializePlayer(Player& p_player, HashTable<string, Room>& p_rooms, Array<Item>& p_items, int p_numItems, std::string& p_filename)
{
ifstream playerfile(p_filename);
int inventorycount = 0;
//all the stuff needed to make a player
std::string name;
int health;
int confidence;
int humor;
int speed;
std::string room;
Room* currentRoom;
Inventory inventory(100);
//reading in values from file
for(int i = 0; i < inventorycount; i++)
{
playerfile.getline(value, 256);
std::string item(value);
for(int j = 0; j < p_numItems; j++)
{
if(p_items[j].GetName() == item)
{
inventory.AddItem(&(p_items[j])); //This line taken out, removes the error.
}
}
}
Player p(name, health, confidence, humor, speed, currentRoom, inventory);
p_player = p;
}
AddItem() takes a pointer to an item, and then appends it to it's DLinkedList.
Edit:
The error I get is
Debug Assertation Failed!
Program: zzz
File f:\dd/vctools/crt_bld/self_x86/crt/src/dbgdel.cpp
Line: 52
Expression: _Block_TYPE_IS_VALID(pHead->nBlockUse)
AddItem() Code:
bool AddItem(Item* p_item)
{
if(p_item->GetWeight() + m_weight <= m_maxWeight)
{
m_inventory.Append(p_item);
m_weight += p_item->GetWeight();
}
else
{
return false;
}
return true;
}
Ok, so we still don't have the code that actually causes the problem, but I'm pretty certain I know what's going on, and to avoid getting into a "20 questions of add more code" - there's two possible scenarios:
Items is an array of objects, and you store pointers to them in your m_inventory container. When destroying this container, the objects are destroyed by calling delete on the items - which doesn't work since the content is not allocated from the heap.
When you copy the inventory the m_inventory container is not appropriately copied, and the contents fall apart because the pointers to the storage is failing.
If this doesn't help, then please try to reduce your code to something that only shows this problem, without using files that we don't know the content of and can be posted as a complete program in the question with all the code necessary [remove any other code that isn't needed], so we can see EVERYTHING. Currently, we're only seeing a few bits of the code, and the problem is almost certainly DIRECTLY in the code you've shown us.