Segmentation Fault 11 in C++ when accessing second element in array - c++

In short, I have a C++ program that consists of a Car class with subclasses SportsCar and SUV, as well as a CarInventory that stores the Car objects.

I think the problem is in the insert function
void CarInventory::insert(Car *car) {
for (int i = 0; i < inventorySize; i++) {
if (carArray[i]) {
i++;
}
When you find a car already in in your carArray you increment i, but then you increment i again in the for-loop. That way you will skip every other position in the array, and they will remain uninitialized.

You allocated an array of 10 cars. But you only initialized it with 4 cars.
So when your loop in displayVehichles gets around to accessing carArray[5] it will likely be accessing uninitialized memory.
This statement seems troublesome:
carArray = new Car *[maxStock];
It should probably be:
carArray = new Car *[maxStock];
for (int i = 0; i < maxStock; i++)
{
carArray[i] = NULL;
}
totalNumCars = 0;
That way, your insert method will behave correctly. But your insert method could be much simpler:
void CarInventory::insert(Car *car) {
if (totalNumCars < maxStock)
carArray[totalNumCars] = car;
totalNumCars++;
}
}
Further, while it's OK the way you have it the cars you have declared go out of scope BEFORE your CarInventory goes out of scope, it will be referencing Car objects that have already been deleted.
Use std::vector to hold your cars:
class CarInventory
{
std::vector<Car*> _cars;
public:
void displayVehicles()
{
for (auto i = _cars.begin(); i != _cars.end(); i++)
{
i->printInfo();
}
}
void insert(Car* car)
{
_cars.push_back(car);
}
};
Now that still doesn't solve the problem of your CarInventory class holding onto pointers of stack objects.
This is even better:
class CarInventory
{
std::vector<std::shared_ptr<Car>> _cars;
public:
void displayVehicles()
{
for (auto i = _cars.begin(); i != _cars.end(); i++)
{
i->printInfo();
}
}
void insert(std::shared_ptr<Car>& spCar)
{
_cars.push_back(spCar);
}
};
Then your code to use the class:
std::shared_ptr<Car*> createCar(const char* vin, const char* make, const char* color, int year)
{
Car* car = new Car(vin, make, color, year);
return std::shared_ptr<Car>(car);
}
int main(int argn, char *argv[])
{
CarInventory cars;
std::shared_ptr<Car*> toyota = createCar("2GCGC34M9F1152828", "Toyota", "Camry", "Green", 2012);
std::shared_ptr<Car*> honda = createCar("1C4BJWAG4DL602733", "Honda", "Civic", "Blue", 2015);
...
CarInventory cars;
cars.insert(toyota);
cars.insert(honda);
cout << "\n";
cars.displayVehicles();
}

Related

How to pass array of object pointers to function?

I am having trouble passing an array of object pointers from main() to a function from different class.
I created an array of object pointers listPin main() and I want to modify the array with a function editProduct in class Manager such as adding new or edit object.
Furthermore, I want to pass the whole listP array instead of listP[index]. How to achieve this or is there any better way? Sorry, I am very new to c++.
#include <iostream>
using namespace std;
class Product
{
protected:
string id, name;
float price;
public:
Product()
{
id = "";
name = "";
price = 0;
}
Product(string _id, string _name, float _price)
{
id = _id;
name = _name;
price = _price;
}
};
class Manager
{
protected:
string id, pass;
public:
Manager(string _id, string _pass)
{
id = _id;
pass = _pass;
}
string getId() const { return id; }
string getPass() const { return pass; }
void editProduct(/*array of listP*/ )
{
//i can edit array of listP here without copying
}
};
int main()
{
int numProduct = 5;
int numManager = 2;
Product* listP[numProduct];
Manager* listM[numManager] = { new Manager("1","alex"), new Manager("2", "Felix") };
bool exist = false;
int index = 0;
for (int i = 0; i < numProduct; i++) { //initialize to default value
listP[i] = new Product();
}
string ID, PASS;
cin >> ID;
cin >> PASS;
for (int i = 0; i < numManager; i++)
{
if (listM[i]->getId() == ID && listM[i]->getPass() == PASS) {
exist = true;
index = i;
}
}
if (exist == true)
listM[index]->editProduct(/*array of listP */);
return 0;
}
Since the listP is a pointer to an array of Product, you have the following two option to pass it to the function.
The editProduct can be changed to accept the pointer to an array of size N, where N is the size of the passed pointer to the array, which is known at compile time:
template<std::size_t N>
void editProduct(Product* (&listP)[N])
{
// Now the listP can be edited, here without copying
}
or it must accept a pointer to an object, so that it can refer the array
void editProduct(Product** listP)
{
// find the array size for iterating through the elements
}
In above both cases, you will call the function as
listM[index]->editProduct(listP);
That been said, your code has a few issues.
First, the array sizes numProduct and numManager must be compiled time constants, so that you don't end up creating a non-standard variable length array.
Memory leak at the end of main as you have not deleted what you have newed.
Also be aware Why is "using namespace std;" considered bad practice?
You could have simply used std::array, or std::vector depending on where the object should be allocated in memory. By which, you would have avoided all these issues of memory leak as well as pointer syntaxes.
For example, using std::vector, you could do simply
#include <vector>
// in Manager class
void editProduct(std::vector<Product>& listP)
{
// listP.size() for size of the array.
// pass by reference and edit the listP!
}
in main()
// 5 Product objects, and initialize to default value
std::vector<Product> listP(5);
std::vector<Manager> listM{ {"1","alex"}, {"2", "Felix"} };
// ... other codes
for (const Manager& mgr : listM)
{
if (mgr.getId() == ID && mgr.getPass() == PASS)
{
// ... code
}
}
if (exist == true) {
listM[index]->editProduct(listP);
}
You cannot have arrays as parameters in C++, you can only have pointers. Since your array is an array of pointers you can use a double pointer to access the array.
void editProduct(Product** listP){
and
listM[index]->editProduct(listP);
Of course none of these arrays of pointers are necessary. You could simplify your code a lot if you just used regular arrays.
Product listP[numProduct];
Manager listM[numManager] = { Manager("1","alex"), Manager("2", "Felix")};
...
for(int i = 0; i < numManager; i++ ){
if(listM[i].getId() == ID && listM[i].getPass() == PASS) {
exist = true;
index = i;
}
}
if(exist == true){
listM[index].editProduct(listP);
}

Getline() and cin manipulate dynamic array

I'm totally lost and confused and could use some help.
I'm currently working on a small command line-based game. For this I wrote a class Inventory, dynamically creating an array of invSpace-objects, each space representing a pair of a pointer to an Item (another class of mine) and a integer, depicting a quantity. Here's the code:
class invSpace {
public:
Item *item;
int quantity;
invSpace() {
item = NULL;
quantity = 0;
}
};
class Inventory {
private:
invSpace* spaces = NULL;
size_t size;
public:
int free_space() {
int free = 0;
for (int i = 0; i < size; i++) {
if (spaces[i].item == NULL) {
free++;
}
}
return free;
}
Inventory() {}
Inventory(size_t new_size) {
size = new_size;
spaces = new invSpace[size];
for (int i = 0; i < size; i++) { //I know this is obsolete because
spaces[i].item = NULL; //of the invSpace constructor, I
spaces[i].quantity = 0; //just did this for testing
}
~Inventory() {
delete[] spaces;
}
invSpace& operator[](int index) {
return spaces[index];
}
};
There are some more methods in this class, like for adding, deleting and searching for items, but those don't matter now. So this is basically just a simple array within one object, dynamically allocating memory in the constructor and with some extra methods. After being created, the array contains zero elements, or Items, so the free_space() method should return the size of the array. But it doesn't. It returns about half of the size.
My first thought was that something went wrong with the allocation. But at a second glance I noticed that the Inventory is totally fine directly after being created; with exactly as many spaces as requested, all of them set to item=NULL/quantity=0. But after a call of getline() at the start of main() that scans user input and saves it to a string for further analyzing, some spaces get filled with random addresses and integers.
Even stranger, with each new call of getline() some spaces are freed, some others filled. As far as my debugging, experimenting and testing goes, none of these addresses belong to any variable in my program, they are just plain random. Also, at no point is there be any interference with the Inventory and the getline() function or the string it returns. In fact, after being created, no part of this object is used anywhere in the code beside the free_space() method. What's even stranger is that spaces in the Inventory class is marked private, so a method is required to meddle with this pointer/array (or so I would expect).
This problem occurs with getline() and cin but not with any of C's <stdio.h> input stream functions. Using malloc() instead of new[] makes no difference. Of course, I could use something like scanf() for the reading from the console. Still, I just want to know why all these things happen. I have absolutely no idea.
Thanks in advance for every answer!
EDIT:
I narrowed the whole code so that it still produces the same error, also changed free_space() so that it prints adress and integer if present:
#include <iostream>
#include <string>
#include <map>
using namespace std;
class Item {
public:
static map<string, Item*> itemlist;
string name;
string description;
Item() {}
Item(const string new_name, const string new_description) {
name = new_name;
description = new_description;
itemlist.insert(pair<string, Item*> (name, this));
}
};
map<string, Item*> Item::itemlist;
/*The more Items are declared, the more random adresses appear in the
inventory*/
Item item01("sword", "A sharp and deadly weapon.");
Item item02("shield", "This will protect you. To a certain extent.");
Item item03("stick", "What is this for exactly?");
Item item04("bottle of water", "A bottle full of refreshing spring water.");
class invSpace {
public:
Item *item;
int quantity;
invSpace() {
item = NULL;
quantity = 0;
}
};
class Inventory {
private:
invSpace* spaces = NULL;
size_t size;
public:
int free_space() {
int free = 0;
for (int i = 0; i < size; i++) {
if (spaces[i].item == NULL) {
free++;
cout << i << " = free" << endl;
}
else {
cout << spaces[i].item << " / " << spaces[i].quantity << endl;
}
}
return free;
}
Inventory() {}
Inventory(size_t new_size) {
size = new_size;
spaces = new invSpace[size];
for (int i = 0; i < size; i++) {
spaces[i].item = NULL;
spaces[i].quantity = 0;
}
}
~Inventory() {
delete[] spaces;
}
};
class Player {
public:
string name;
Inventory inventory;
Player(const string new_name) {
inventory = Inventory(40);
name = new_name;
}
};
Player player("Me");
int main() {
string input;
//Inventory inventory(40); //no error when declared outside the Player class
while (1) {
cout << "\n>> ";
getline(cin, input);
if (input == "x") {
break;
}
else {
player.inventory.free_space();
}
}
}
Some things I noticed: No error occurs if the inventory isn't part of a Player-object. If it is but no Items are declared only the first inventory space receives a random adress (and int value) after the first call of getline().
The more Items there are, the more random adresses I get, it seems...

C++ Program crashes when accessing object after copy

I'm having a problem which I think is related to creating a copy of an object. I have a map class that contains a std::map with a bunch of classes defining the different tile types indexed by their ID, and a bunch of tiles in a vector each with a pointer to one of those classes. Additionally I have another class, Scenario, that contains the map.
The problem comes when I create a Scenario object and try to do anything with its map. There must be some problem when copying the pointers but I haven't been able to figure it out.
I have tried to reduce the code to what's necessary to reproduce the problem:
#include <string>
#include <map>
#include <vector>
#include <iostream>
using namespace std;
class TileInfo {
string name;
public:
int id;
TileInfo() {};
TileInfo(int id, string name);
string getName() const;
};
TileInfo::TileInfo(int id, string name)
{
this->id = id;
this->name = name;
}
string TileInfo::getName() const
{
return name;
}
class Tile
{
public:
TileInfo* info;
Tile() {};
Tile(const Tile & other, map<int,TileInfo> & info);
Tile (TileInfo* info);
string getName() const;
};
Tile::Tile (TileInfo* tileInfo)
{
this->info = tileInfo;
}
Tile::Tile( const Tile & other, map<int,TileInfo> & tileInfo )
{
map<int,TileInfo>::iterator it = tileInfo.find(other.info->id);
if(it == tileInfo.end())
this->info = NULL;
else
this->info = &(it->second);
}
string Tile::getName() const
{
return info->getName();
}
class Map
{
vector <vector <Tile>> tiles;
map <int, TileInfo> tileInfo;
public:
void print() const;
Map() {};
Map(map<int,TileInfo> tileInfo);
Map(const Map & other);
string getName() const;
void loadTiles();
};
Map::Map(map<int,TileInfo> tileInfo)
{
this->tileInfo = tileInfo;
}
Map::Map(const Map & other)
{
this->tileInfo = other.tileInfo;
for(unsigned int i = 0; i < other.tiles.size(); i++)
{
vector<Tile> line;
for(unsigned int j = 0; j < other.tiles[i].size(); j++)
{
Tile tmpTile = Tile(other.tiles[i][j],tileInfo);
line.push_back(tmpTile);
}
this->tiles.push_back(line);
}
}
void Map::print() const
{
for(unsigned int i = 0; i < tiles.size(); i++)
{
for(unsigned int j = 0; j < tiles[i].size(); j++)
{
cout << "Tile at " << i << ", " << j << " is a "; cout << tiles[i][j].getName() << endl;
}
}
}
void Map::loadTiles()
{
for(unsigned int i = 0; i < 3; i++)
{
vector <Tile> line;
for(unsigned int j = 0; j < 3; j++)
{
map<int,TileInfo>::iterator ite = tileInfo.find(i);
if( ite!=tileInfo.end())
line.push_back(Tile(&(ite->second)));
else
{
line.push_back(Tile(NULL));
}
}
tiles.push_back(line);
}
}
class Scenario
{
public:
Map map;
Scenario() {};
Scenario(Map map);
};
Scenario::Scenario(Map map)
{
this->map = map;
this->map.print();
}
Map createMap()
{
map<int,TileInfo> tmpInfo;
for(unsigned int i = 0; i < 3; i++)
{
tmpInfo.insert(pair<int,TileInfo>(i,TileInfo(i,"testname")));
}
Map rtrnVal = Map(tmpInfo);
rtrnVal.loadTiles();
return rtrnVal;
}
int main()
{
Map newMap = createMap();
Scenario newScenario = Scenario(newMap);
newScenario.map.print();
int input;
cin >> input;
}
The print() at the end of the Scenario constructor prints the map's contents correctly, but the one after the scenario is assigned causes a crash. Any help would be appreciated.
The original std::map where your original TileInfo objects are stored is here:
map<int,TileInfo> tmpInfo;
for(unsigned int i = 0; i < 3; i++)
{
tmpInfo.insert(pair<int,TileInfo>(i,TileInfo(i,"testname")));
}
That is the map the houses the pairs. you then make a copy of said map. It creates copies of all your TileInfo objects, which is ok.
Map rtrnVal = Map(tmpInfo);
But this is where the wheels begin to come off. You fire loadTiles here, which sets up your map of vectors that addres the relative TileInfo objects in rtrnVal. This code:
rtrnVal.loadTiles();
leads to this code. Note that you're pushing the addresses of your mapped TileInfo objects into your vectors. The map where these reside is this objects map.
void Map::loadTiles()
{
for(unsigned int i = 0; i < 3; i++)
{
vector <Tile> line;
for(unsigned int j = 0; j < 3; j++)
{
map<int,TileInfo>::iterator ite = tileInfo.find(i);
if( ite!=tileInfo.end())
line.push_back(Tile(&(ite->second)));
else
{
line.push_back(Tile(NULL));
}
}
tiles.push_back(line);
}
}
Finally, back where we started you do this:
return rtrnVal;
This makes a copy of the Map, which makes a copy of the map of vectors, which contain pointers to the TileInfo in the map within rtrnVal that is about to be destroyed on function exit. The result back on the caller side.
Map newMap = createMap();
newMap now holds dangling pointers to TileInfo objects that were in rtrnVal in createMap.
Possible Solution
Rather than having a map of vectors containing pointers to TileInfos, consider a map of vectors of indexes, where each index keys to a 0-based slot in a TileInfo std::vector that is contained along side the map. I can see what you were trying to do (singular TileInfos shared across multiple cells) so you still reap that benefit. The vector will come along for the ride wherever the map does (they're owned by the same Map object) and copying won't harm anything because both the map (of indexes) and the vector (of TileInfo) will copy safely. In the end you still get what you want (singular TileInfos) but now-indexed by number rather than pointer. As a bonus, you don't have to deal with rebasing pointers to TileInfo from one map to another in a custom copy-ctor. Its all relative (0.. n-1)
Best of luck.
You're storing pointers to TileInfo:
class Tile
{
public:
TileInfo* info;
...
But once the object is copied, the pointers are copied across, but the TileInfo that they pointed to have been destructed, so they are referencing invalid memory = crash.
Consider implementing the copy constructor / copy operator to handle it.

Passing struct between functions C ++

I've searched but haven't been able to get what I want...
I'm doing a little game. And I got this struct that contains the player details.
struct Player
{
string name;
int level;
int exp;
int hp; // life
int mp; // mana
int shield;
};
And when in the menu, the user chooses to start a new game, it goes to this function:
int StartNewPlayer(string name)
{
Player player;
player.name = name;
player.level = 1;
player.exp = 0;
player.hp = 20;
player.mp = 5;
player.shield = 0;
*pass/return the struct here*
}
Then I have a function that prints the game board, and where I should use the data from the new player struct, for example:
void game_board ()
{
cout << "Hello!" << player.name;
(...)
}
Finally, somewhere in main I have:
int main ()
{
StartNewPlayer(new_game());
game_board();
}
that calls all the functions above.
But I can't figure it out... I tried references, pointers without luck.. I need some help here please...
How about this?
Player StartNewPlayer(string name)
{
Player player;
player.name = name;
player.level = 1;
player.exp = 0;
player.hp = 20;
player.mp = 5;
player.shield = 0;
return player;
}
void game_board(Player player)
{
cout << "Hello!" << player.name;
(...)
}
int main ()
{
Player player = StartNewPlayer(new_game());
game_board(player);
}
Do not create extra copies of the data with complex datatypes by using pass-by-value
Use pointers instead to pass the address of the variable that can be modified in the function. The changes will be reflected in the caller's function as well.
void StartNewPlayer(string name, Player *player)
{
player->name = name;
player->level = 1;
player->exp = 0;
player->hp = 20;
player->mp = 5;
player->shield = 0;
}
void game_board(Player* player)
{
cout << "Hello!" << player->name;
(...)
}
int main ()
{
Player player;
StartNewPlayer(new_game(), &player);
game_board(&player);
}
Alternative using pass-by-reference:
If you're a fan of references, (which is just a clever compiler-trick that makes use of pointers internally again):
void StartNewPlayer(string name, Player& player)
{
player.name = name;
player.level = 1;
player.exp = 0;
player.hp = 20;
player.mp = 5;
player.shield = 0;
}
void game_board(Player& player)
{
cout << "Hello!" << player.name;
(...)
}
int main ()
{
Player player;
StartNewPlayer(new_game(), player);
game_board(player);
}
I would suggest returning a pointer to a Player struct. If you return a "reference" like you are doing right now, it will call the copy constructor of Player which can lead to further complications.
Normally, at the end of StartNewPlayer(...), the Player you declared there will cease to exist as the object scope will end, so when you return it, the c++ compiler gets that you want to keep the object alive and will create a copy for you, invisibly. If you return a pointer to it, you really are returning the object you allocated in your function.
Suppose that you have pointers in your Player structure, such as
struct Player
{
int level;
char* name; //lets assume you did it like that
}
When you are returning the Player, the int will be copied, but the char* will not. ints are easy to handle while char* need all kind of tricky functions like strlen and strncpy. The more complex your Player struct becomes, the more problem you will face by using the default copy constructor.
Another solution would be to declare a copy constructor yourself for the Player struct ( really, you could use classes since they are mostly interchangeable in c++ ).
Player(const Player& p)
{
name = p.name;
level = p.level;
// and so forth
}
So I would use
Player* StartNewPlayer(std::string name)
{
Player* player = new Player();
player->name = name;
player->level = 1;
// snip
return player;
}
At the end of your program, be sure to delete player otherwise you will have a memory leak

How to assign a dynamic array of pointer returned from a function, to a variable?

Please have a look at the following code
Vehicle ** damagedVehicles(Vehicle **vehicles, int size)
{
Vehicle **damaged = new Vehicle *[size];
for(int i=0;i<size;i++)
{
int d = vehicles[i]->damage;
if(d>=35)
{
damaged[i] = vehicles[i];
}
}
return damaged;
}
int main()
{
Vehicle **damagedVehicles = damagedVehicles(vManager->getList(), vManager->getCount());
}
As you can see, my attemt in the main is not working. How can I assign that array of pointers to a variable?
Rename the variable so it doesn't clash with the name of the function?
Vehicle **myDamagedVehicles = damagedVehicles(vManager->getList(), vManager->getCount());