Need Help Solving a Memory Leak - c++

I am writing an inventory management system using dynamic arrays using objects. The strategy for this is NOT to use vectors, but allocate a dynamic array that 1 increment by 1 every time the client needs to add to the inventory. I am getting a "segmentation fault" error so I believe it is a memory leak.
I have tried rewriting it to match addresses but no luck. I think the buildItem function produces a temporary object, which is destroyed when the function ends. I don't know how to fix this though.
#include <iomanip>
#include <iostream>
#include <string>
using namespace std;
class InventoryObject {
private:
int itemNumber;
string description;
int qty;
float price;
public:
int getItemNum() { return itemNumber; }
string getDescription() { return description; }
int getQty() { return qty; }
float getPrice() { return price; }
void storeInfo(int p, string d, int q, float pr);
void showValues(InventoryObject &item);
};
// Function Implementation
void InventoryObject::storeInfo(int p, string d, int q, float pr) {
itemNumber = p;
description = d;
qty = q;
price = pr;
}
void InventoryObject::showValues(InventoryObject &item) {
cout << fixed << showpoint << setprecision(2) << endl;
cout << "Part Number : " << item.getItemNum() << endl;
cout << "Description : " << item.getDescription() << endl;
cout << "Quantity: : " << item.getQty() << endl;
cout << "Price : " << item.getPrice() << endl << endl;
}
// Function Prototypes for Client Program
InventoryObject buildItem();
void drawMenu();
void showValues(InventoryObject &);
void printInventory(int size);
int main() {
int size = 1;
int choice;
bool quit = false;
InventoryObject part;
InventoryObject *iArray = new InventoryObject[size];
drawMenu();
cin >> choice;
while (quit == false) {
if (choice == 1) {
InventoryObject item;
item = buildItem();
iArray[size] = item;
}
if (choice == 2) {
iArray[size].showValues(iArray[size]);
}
if (choice == 3) {
quit = true;
}
}
return 0;
}
// This function accepts the data from the client and creates a new
// InventoryObject object. The object is then supposed to be added to the
// dynamic array.
InventoryObject buildItem() {
InventoryObject *tempObject = new InventoryObject;
int itemNum;
string description;
int qty;
float price;
cout << "Enter data for the item you want to enter:\n\n";
cout << "Item Number: \n";
cin >> itemNum;
cout << "Description: \n";
cin.get();
getline(cin, description);
cout << "Quantity: \n";
cin >> qty;
cout << "Unit price: \n";
cin >> price;
tempObject->storeInfo(itemNum, description, qty, price);
return *tempObject;
}
void drawMenu() {
cout << "1. Add Inventory\n";
cout << "2. Display Inventory\n";
cout << "3. Quit Program\n";
}
I expect the object to be created, and put into the dynamic array. Then redraw the menu and interact with the client from there.

The main problem is that you are writing past the area of memory you allocated for your array (iArray).
Specifically, this line of code:
iArray[size] = item;
Should actually be:
iArray[size - 1] = item;
The above does not cause memory leak, but something else you do in your program does:
Your function buildItem does this when it returns the value of a pointer without first deleting the pointer.
To fix this, change
InventoryObject *tempObject = new InventoryObject;
to
InventoryObject tempObject;
And finally, remember to delete iArray before return 0; in main
delete[] iArray

Build your program with debug symbol (-g flag)
Run limit-c unlimited
Run your program until it crashes
Run gdb core where is the name of your program
In the gdb climate type bt.
You should now have a back trace of where your program is crashing

Daniel, here my observations:
The function buildItem must return a pointer of InventoryObject i mean: InventoryObject*. It is bease you are returning the pointer of the memory that was reserved at the moment of create it (InventoryObject *tempObject = new InventoryObject;), like this:
InventoryObject* buildItem() {
InventoryObject *tempObject = new InventoryObject;
//...
tempObject->storeInfo(itemNum, description, qty, price);
return *tempObject;
}
keep in mind that your main array (InventoryObject *iArray) contains an array of pointer.
The main problem that i see. In the main you are using an if block where there is a local variable called item (InventoryObject item). Let me explain something: Each instance of a class, like you InventoryObject item will be destroyed, release its memory, if its context is over.
So, in this case, the problem is that you was casting the pointer of at the moment of returning from the function buildItem (return *tempObject) and store its value into a local variable InventoryObject item which shall be release when the thread leaves the if, the context of the local variable.
Change your local variable InventoryObject item to handle a pointer: InventoryObject* item
if (choice == 1) {
InventoryObject* item;
item = buildItem();
iArray[size] = item;
}
I recommend you to read the chapters 7. Pointers, Arrays, and References and 17 Construction, Cleanup, Copy, and Move from the book The C++ Programming Language of Bjarne Stroustrup.

I have tried rewriting it to match addresses but no luck. I think the buildItem function produces a temporary object, which is destroyed when the function ends.
Your intuition is half true. There is something wrong with this function, but it has nothing to do with temporaries. It's more about you allocating an object you never destroy.
The problem is that you are trying to do something similar to what I was trying to do in this question, but not quite. Even if you were doing what I was doing, it still wouldn't be a good idea for reasons that lots of people already explained better than I could.
The point is is that the base of the issue is that is if you use new to allocate something, you must use delete to deallocate it, which you don't do here.
InventoryObject buildItem() {
InventoryObject *tempObject = new InventoryObject;
//...
return *tempObject;
}
You simply return the object by value without deleting it first. You aren't even returning it by reference which would be better (yet still probably bad: again, see my question). You are allocating an object and never deleting it. That's a leak.
You have two solutions: either return the pointer directly (if you really need a pointer) like this:
InventoryObject* buildItem() {
InventoryObject *tempObject = new InventoryObject;
//...
return tempObject;
}
Or, you can simply just return the object by value like this:
InventoryObject buildItem() {
InventoryObject tempObject;
//...
return tempObject;
}
Given the code sample you've shown, this is my recommendation of the two.
Note: I should mention that if for some reason you do need to return a pointer and have some factory method pattern with some sort of polymorphism in play, you also have the option of smart pointers too. That is what I ended up doing based on other people's suggestions from the other thread. I can personally recommend it. Basically, your code code would become something like this instead:
std::unique_ptr<InventoryObject> buildItem() {
std::unique_ptr<InventoryObject> tempObject = new InventoryObject; // C++11 way, I think
// C++14 and above has a function called make_unique you could use instead.
//...
return tempObject;
}
However, this is only useful if you have some sort of polymorphism going on as I did. Given the code sample you have posted so far, you really only need to return by value in your situation. I just thought I'd mention this other option too, just in case.
P. (P.) S. This answer is only about your suspected memory leak. That said, there are other helpful answers here that you should heed. Problems described in other answers could contribute to your problem and could really trip you up down the road (actually, could still trip you up now too) if you don't fix them, so I highly recommend taking their advice too.

Related

Why does the value in classRosterArray seemingly persist after I delete in the 'remove' function?

in Main.cpp I call the add function which adds student objects to classRosterArray
roster.add(id, firstName, lastName, email, age, daysInCourse1, daysInCourse2, daysInCourse3, degree);
roster.remove("A3");
Relevant part of add function in Roster.cpp:
Student* student = new Student(studentID, firstName, lastName, emailAddress, age, degreeprogram, daysInCourses);
classRosterArray[numberOfStudentsAdded] = student;
In the 'remove' function a studentID is passed in. If it matches a studentId in classRosterArray then that value is deleted:
void Roster::remove(string studentID) {
for (int i = 0; i < 5; i++) {
if (classRosterArray[i]->getId() == studentID) {
cout << "removed: " << studentID << endl;
delete classRosterArray[i];
printAll();
return;
}
else {
cout << "The student with the ID: " << studentID << " was not found\n";
}
}
}
edited to add in printAll() function
void Roster::printAll() {
//prints a complete tab-separated list of student data, each data point indented (tab)
for (int i = 0; i < 5; i++) {
classRosterArray[i]->print();
}
}
But printAll() still prints all values regardless. What am I doing wrong?
delete classRosterArray[i];
After this line, classRosterArray[i] will be an invalid pointer (or null if it was before deletion). After this, you call printAll() which contains:
classRosterArray[i]->print();
Here, you attempt to access an object through an invalid pointer. The behaviour of the program is undefined.
What am I doing wrong?
You are indirecting through an invalid pointer. That's wrong. Don't do that. To fix the program, remove the call to printAll(); from remove.
Another thing you're doing wrong: You unnecessarily use bare owning pointers. Don't do that. Probably, classRosterArray should actually be std::vector<Student>. Or, since you're doing search based on a key, perhaps std::unordered_set<std::string, Student> would be appropriate.
delete classRosterArray[i]; is not how you remove something from an array
you do not show how that array is implemented. I hope it is a std::vector, if so you need to use erase
I also hope that the contents of the arrray are std::unique_ptr
but way better would be to put the objects in a std::map with studentID being the key

C++ Vector of Objects, are they all named temp?

New to C++ OOP, I recently learned about classes and objects. I created a straightforward class and menu-driven program that adds a temp object to a vector of movies. I have a quick question that I can't quite understand.
Am I just pushing multiple "temp" objects into the vector?
In my head i'm visualizing this as vector my_movies = {temp, temp, temp}; and continously adding 'temp' objects until the user is done. Is this the right way to picture it?
#include <iostream>
#include <vector>
using namespace std;
class Movie
{
private:
string name;
public:
string get_name() { return name; }
void set_name(string n) { name = n; }
};
void menu() {
cout << "1. Add movie" << endl;
cout << "2. Show Movies" << endl;
cout << "3. Quit" << endl;
}
int getChoice(int &choice) {
cout << "Enter you choice: ";
cin >> choice;
return choice;
}
int main() {
vector<Movie> my_movies;
int choice = 0;
string name;
do {
menu();
getChoice(choice);
switch (choice) {
case 1: {
Movie temp;
cout << "Set user name: ";
cin >> name;
temp.set_name(name);
my_movies.push_back(temp);
break;
}
case 2: {
for (auto &mv : my_movies)
cout << mv << endl;
break;
}
}
} while (choice != 3);
return 0;
}
In your case, when you are calling push_back it will copy your "temp" object, which is a local object on the stack. It will be copied into a new object which is stored on the heap, held by the vector object. The vector will store these as an array internally (the default vector with the default allocator etc).
It's also possible to "move" the object (under C++11 and later), if you understand the difference, but doing push_back(std::move(temp)), which generally gives better performance. In your case it would avoid copying the string member "name", and move it instead, avoiding a new allocation for the string inside the Movie in the vector.
See here for more details on push_back
Appends the given element value to the end of the container.
The new element is initialized as a copy of value.
https://en.cppreference.com/w/cpp/container/vector/push_back
If you are just talking about the name of the movie, it will be what ever is entered from cin. Objects don't have names themselves. The local variable name "temp" is just what you see when you write the code, but is just used to tell the compiler which object is being used - the object itself doesn't have a name form the compilers perspective.

Writing an object with a pointer to another object to an ASCII file (C++)

I'm making a program that keeps track of different employees. Some of the employees have partners (wifes and husbands), so all of the Employee objects have a data member called "Partner* partner" (a pointer to a Partner object).
My problem comes when I want to write an Employee to a file. I can successfully write all of the Employee data (name, address, birth date etc.) to the file, but I don't know how to write the partner to file. I have a function in the Partner class called "writeToFile" which outputs all of the partner data, but I don't know how to "connect" it to the correct Employee object. I tried to just output the "partner"-object to the end of the file, but that just added a bunch of zeros.
Should I use two separate files (one for employees and one for partners), or should I just append the partner data to the employee data? Wouldn't that mess up the file structure when reading it back in, since only some of the employees have partners and some of the partner objects just point to NULL?
My classes inherits each other, so both the Partner and Employee class inherits the Adult class, which again inherits the Person class.
Can anyone give me a "pointer" to what is the best way of writing an object which has a pointer to another object inside it? Here's my temporary code btw, if it is of any interest:
#include <iostream>
#include <fstream>
#include <cstring>
#include <cctype>
#include <cstdlib>
using namespace std;
const int MAXTXT = 80;
class Person {
protected:
char* firstname;
char birthdate[6];
public:
Person() {
char fname[MAXTXT];
cout << "First name: "; cin.getline(fname, MAXTXT);
firstname = new char[strlen(fname + 1)];
strcpy(firstname, fname);
cout << "Birth date (DDMMYY): ";
cin >> birthdate; cin.ignore();
}
void display() {
cout << "\nFirst name: " << firstname;
cout << "\nBorn: " << birthdate;
}
void writeToFile(ofstream & ut) {
ut << firstname << "\n" << birthdate;
}
};
class Adult: public Person {
protected:
char* lastname;
public:
Adult() {
char lname[MAXTXT];
cout << "Last name: "; cin.getline(lname, MAXTXT);
lastname = new char[strlen(lname + 1)];
strcpy(lastname, lname);
}
void writeToFile(ofstream & out) {
out << "\n" << lastname << "\n";
}
void display() {
cout << "\nLast name: " << lastname;
}
};
class Partner: public Adult {
private:
int phone1;
int phone2;
public:
Partner() {
cout << "Phone (mobile): "; cin >> phone1;
cout << "\nPhone (job): "; cin >> phone2; cin.ignore();
}
void writeToFile(ofstream & out) {
Person::writeToFile(out);
Adult::writeToFile(out);
out << "\n" << phone1 << " " << phone2;
}
void display() {
Person::display();
Adult::display();
cout << "\nPhone (mobile): " << phone1;
cout << "\nPhone (job): " << phone2;
}
};
class Employee: public Adult {
private:
int nr;
char* address;
Partner* partner;
public:
Employee() {
}
Employee(int n) {
char adr[MAXTXT];
nr = n;
cout << "Address: "; cin.getline(adr, MAXTXT);
address = new char[strlen(adr + 1)];
strcpy(address, adr);
partner = NULL;
}
void changePartner() {
Partner::Partner();
}
void writeToFile(ofstream & out) {
Person::writeToFile(out);
Adult::writeToFile(out);
out << nr << "\n" << address << endl;
}
void display() {
Person::display();
Adult::display();
cout << "\nAddress: " << address;
if(partner) {
partner->display();
}
}
int returnEmpNr() {
return nr;
}
};
Employee* employees[100];
int lastUsed = 0;
int main() {
}
void writeToFile() {
ofstream outfile("EMPLOYEES.DAT");
ofstream outfile2("PARTNERS.DAT");
outfile << lastUsed << "\n";
for(int i = 1; i <= lastUsed; i++) {
employees[i]->writeToFile(outfile);
}
A pointer is meaningless except to a single run of a program and could very well be meaningless by the time the file is read if the pointer at value has gone out of scope. The odds of the same Partner being in the same spot in memory, assuming space has even been allocated for it, the next time around could be as bad as 1 in 18,446,744,073,709,551,616 and being wrong has often fatal results. And those fatal results mean you got lucky. You could smash perfectly valid memory that belongs to something else, and results in behaviour that is weird, undefined, and much harder to debug than an outright crash.
In C++ pointers are often a sucker bet. Use them as a last resort because they can really ramp up the amount of code you need to write.
I recommend two lists (but not necessarily two files. Both lists can easily exist in one file) one of Partners and one of Employees. The Partners don't seem to need to know about the Employees, so save yourself some trouble and write out and read in the partner list first.
When writing the Employee list, don't store the Partner pointer because it won't work. Instead store the index of the Partner in the Partner list. Then when you read the Employee list, you can read the Partner's position in the Partner table look up that Partner, and point to them. This is why it's much easier to write and read the Partners first; it is hard to look up data in a list that hasn't been read yet.
Or ditch the concept of Partner pointers entirely and always use the index to look the Partner up. This is much safer approach, so long as you always append new partners to the list and never insert into the list or do something silly like shuffle the list.
While we're messing with pointers, take a good solid read of "What is The Rule of Three?" because you are heading into a quagmire of memory management carnage.
As written every time you copy an Employee, you will get another Employee that is copied stupidly. It copies the pointers, not the content, so you now have 2 Employee objects pointing to the same names and Partners. When you free the memory allocated to the partner and names, which you don't and really, really should, the other copy is pointing at memory that your program no longer owns and becomes a ticking time bomb just waiting to crash your program.
Using a std::vector<Partner> (note it is a vector of Partner, not Partner *. This allows the vector to own and manage all of the memory for you and not just the memory needed by the list) and indexes clears up the problem with Partners, because the std::vector manages the memory for you, but the names are still waiting to kill the program. Replacing the char *s with std::string will solve that problem, also by moving the memory management burden from your code to std::string where it was written for you some time in the 1990s and has been under use in millions of programs ever since. Not many bugs left to trip over after 20 years.
If you have to use pointers and arrays of pointers, you need to make custom destructors, copy constructors, move constructors, assignment operators and move operators. That's a lot of extra work.
But those vectors and strings contain pointers and you have to handle writing them carefully. This topic, serialization, has been beaten to death elsewhere, so here's a link to a reputable site that can probably handle it better than I can.

Access Violation writing location 0xCDCDCDCD

I am trying to make a small linked list using one structure "students" and another sturcture "stack", which holds the student structure and the pointer to the next element.
However i constantly keep getting a memmory access error. I double checked to make sure all pointers are initialized (only one pointer, Stacktop, initialized to NULL)
Here are the structure definitions:
#include <stdio.h>
#include <string>
#include <iostream>
#include <stdlib.h>
using namespace std;
struct students
{
int matnr;
string name;
};
struct stack
{
students stud;
stack *next;
};
typedef struct stack Stack;
typedef Stack *ptrStack;
void push(students s);
students pop();
int isEmpty();
void printStack(students stud);
Here is the push function (which keeps crashing the programm)
#include "stack.h"
ptrStack Stacktop = NULL;
void push(students s)
{
ptrStack stack = (ptrStack)malloc(sizeof(Stack));
if (stack == NULL)
{
cout << "!!FIN!!" << endl;
return;
}
stack->stud = s;
stack->next = Stacktop;
Stacktop = stack;
return;
}
And here is the main:
#include "stack.h"
students readStuds()
{
students s;
cout << "Enter Student name: " << endl;
cin >> s.name;
cout << "Enter Matr Nr: " << endl;
cin >> s.matnr;
return s;
}
int main()
{
char c;
do {
push(readStuds());
cout << "Continue Entering Students? " << endl;
cin >> c;
cout << "----------------------" << endl;
cout << "----------------------" << endl;
} while (c != 'q');
cout << " POPPING STACK " << endl;
cout << " ............. " << endl;
while (isEmpty())
{
printStack(pop());
}
}
This:
ptrStack stack = (ptrStack)malloc(sizeof(Stack));
allocates enough memory to hold a struct stack a.k.a Stack, but malloc() does not do anything to initialize the memory that is returned. So, in particular, the string inside your new stack contains random garbage, which will then be interpreted by your cin >> s.name, and assumed to be a valid string, which it isn't, so the code fails.
Solution - use ptrStack stack = new Stack instead. Even better, write proper constructors/destructors, copy constructors, assignment operators, etc...
The problem is that you're mixing C and C++, specifically in this line of code
ptrStack stack = (ptrStack)malloc(sizeof(Stack));
The Stack structure contains an object of type string. The string constructor must be called before you can use the string. If you allocate memory using the C++ new operator, then the constructor is automatically called, and the string is properly initialized.
But if you allocate memory using the C malloc function, then the string constructor is not called. The 0xCDCDCDCD comes from an uninitialized pointer in the string object that should have been initialized by the constructor (but wasn't because the constructor was not called).
The moral of the story: don't mix C and C++ until you have a lot of experience in both.
You're doing:
ptrStack stack = (ptrStack)malloc(sizeof(Stack));
^^^^^
which is defined as:
typedef Stack *ptrStack;
therefore, sizeof(Stack) is essentially size(pointer). You're not allocating enough memory for your structure, you're allocating enough memory for a POINTER to your struct. So yes, you are running off the end of your allocated memory

How to use strings in if statements in c++?

The problem with this code is that there are no errors showing, but when i compile the program, the if else statements do not carry out as they should do. Both if statements show the same answer, for example the second if statement. If I type Y or N then I get the same thing, 'You will now choose an event'. How do i get rid of this problem? Is char supposed to be used or string?
#include <iostream>
#include <iomanip>
#include<stdlib.h>
class start
{
public :
void getusertype ();
void registeruser ();
start();
protected :
char consumer_name[20],
consumer_address[30],
consumer_email[30];
char user[8];
};
start::start()
{
char terminator;
cout <<"Are you the venue manager, consumer or ticket agent?";
cin.get(user,8);
cin.get(terminator);
}
void start::getusertype ()
{
char terminator;
if(user[8])
{
cout <<"You have now entered the system." <<endl <<endl;
cin.get(terminator);
}
else
{
cout <<"You can only enter this part of the system if you are a consumer.";
}
}
void start::registeruser()
{
char option[1];
cout <<"Are you registered? (Enter Y/N)";
cin.get(option,1);
if (option=="N")
{ char terminator;
cout <<"Please enter your registration details" <<endl <<endl;
cout << " Enter your full name: " <<endl;
cin.get (consumer_name,20);
cin.get(terminator);
cout <<"Enter your address: " <<endl;
cin.get(consumer_address,30);
cin.get(terminator);
cout <<"Enter your email address: " <<endl;
cin.get(consumer_email,30);
cin.get(terminator);
}
else
{
cout <<"You will now choose an event.";
}
}
If you really want to use char [] rather than std::string (which has an operator== and clearly acts more like what you expect) you'll need to edit your if statement to use the old C-way of doing string comparisons. Something like:
if ( strcmp(option, "N") == 0)
{
// ...
}
Or since you are comparing only one character you could just do:
if ( *option == 'N' )
{
// ...
}
This dereferences the pointer to the first character in that char [] which is a primitive type and so can be compared directly with ==.
char option[1]; ... if (option=="N")
The 'if' statement compares the address of the option array with address of a constant string; they will never be equal.
Writing in C style, you could write something like if (strcmp(option, "N") == 0) or several other things. But it would be better to get used to using std::string in C++ code; and it's more direct. If option was a std::string, your 'if' statement would have been correct.
Take, for example
if (option=="N")
This compares option, decayed to a pointer, to the address of the literal "N". That will always return false. To compare the contents of C strings you need to use strcmp.
Do yourself an enormous favour and use std::string instead of C strings.
You are using 'C' strings - that end of the day are just pointers. So you need to use the function strcmp - but std::strings will save the hassle.
To understand why this doesn't work, you need to know a few things about how pointers work.
What is a pointer?
A pointer is a type that points to a value. So when you declare a variable with a type char:
char foo;
char* bar = &foo;
You are reserving a chunk of memory to store a character. The variable bar points to the variable foo. You can get the value stored in foo by using it directly or dereferencing the variable bar (*bar).
When you declare a variable with a char pointer type:
char* foo
You are reserving a chunk of memory to store a chunk of memory to store a character.
But I never made pointer!
In C/C++, an array can be implicitly converted into a pointer. This is not what actually happens with the code you wrote, but you can think of it like this:
char optionValue;
char* option = &optionValue;
Why does my if statement not work?
When you compare pointers, you compare the chunk of memory you are pointing to with the other pointer's chunk of memory. So == will only return true if the two pointers point to the same chunk of memory. In your code, this is impossible: the constant "N" will never be the same as the pointer that points to the chunk of memory the compiler created for you.
What you need to do is compare the content of the chunks of memory (by using strlen as suggested by other people) or changing the type of the variable (strings are very common, so there is a std::string type to deal with them).
How do i get rid of this problem?
Stop using character arrays.
where do i call std::string ?
Like this:
#include <iostream>
#include <iomanip>
#include <string>
#include <limits>
class start
{
public :
void getusertype ();
void registeruser ();
start();
protected :
std::string consumer_name;
std::string consumer_address;
std::string consumer_email;
std::string user;
};
start::start()
{
std::cout <<"Are you the venue manager, consumer or ticket agent?";
std::getline(std::cin, user);
}
void start::getusertype ()
{
if(user == "consumer")
{
std::cout <<"You have now entered the system.\n\n";
}
else
{
std::cout <<"You can only enter this part of the system if you are a consumer.\n";
}
}
void start::registeruser()
{
std::string option;
std::cout <<"Are you registered? (Enter Y/N)";
std::cin >> option;
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
if (option=="N")
{
std::cout <<"Please enter your registration details\n\n";
std::cout << " Enter your full name: \n";
std::getline(std::cin, consumer_name);
std::cout <<"Enter your address: \n";
std::getline(std::cin, consumer_address);
std::cout <<"Enter your email address: \n";
std::getline(std::cin, consumer_email);
}
else
{
std::cout <<"You will now choose an event.\n";
}
}