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
Related
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.
I made a simple array of struct I made a function to implement the array from users input
but I am struggling to find the right way to free or delete elements in the array ;
here is my code for a better understanding
#include <iostream>
using namespace std;
typedef struct InfStudent
{
int id;
int age;
int lvel;
}studentInfo;
void addElments(studentInfo *s)
{
int i=0;
for(i=0; i<2; i++) {
s[i].id = i;
s[i].age = i * i + 1;
s[i].lvel = i + i + 2;
}
}
int studCounter = 0 ;
void deltetElement(void *studentInfo1 ) {
for (int i = 0; i < 6; i++) {
cout << "empty " << endl;
free(studentInfo1);
}
}
int main()
{
int n;int i;
studentInfo st[2];
addElments(st);
for(i=0; i<2; i++) {
cout<<"enter the Id number of the student "<< endl;
cin >> st[i].id;
cout<<"enter the age of the student "<< endl;
cin >> st[i].age;
cout<<"enter the level of the student "<< endl;
cin >> st[i].lvel;
}
deltetElement(st);
for(i=0; i<2; i++) {
cout << "Id of the student " << i << "\t=" << st[i].id;
cout << "\t Age of the student " << i << "\t=" << st[i].age;
cout << "\tLevel of the student " << i << "\t=" << st[i].lvel;
cout<< endl;
}
return 0;
}
the output
enter the Id number of the student
1234
enter the age of the student
32
enter the level of the student
2
enter the Id number of the student
321
enter the age of the student
2
enter the level of the student
32
empty
it is printing empty, but the code still working like 3 second and then printing empty massage, but I did not understand it does delete or not, or there is a better way to do that;
Since you are using studentInfo st[2]; it's an array of VALUE types, meaning that studentInfo objects are not allocated in heap, and should not be deleted by free() or delete.
free or delete array of strcut c++
You create an array with automatic storage. Automatic objects are destroyed and their storage is released automatically when the variable goes out of scope. You cannot and you must not "free" them in any way other than by letting the execution proceed to the outside of the scope where the automatic object is defined.
Only thing that may be passed to free is a pointer that was returned by malloc (or certain other related C allocation functions) and hasn't previously been freed. Since that doesn't apply to what you pass to free, the behaviour of your program is undefined. That's bad. Don't do that.
P.S. Don't use malloc nor free in C++ if you can avoid it (and it can usually be avoided).
I am struggling to find the right way to free or delete elements in the array ;
The elements of an array are destroyed and their storage released when the array itself is destroyed and its memory is released. There is no way to separate those two.
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.
I am trying to write a program to print a vector of object pointers backwards.
My instructions for the part of the lab im stuck on:
Function main() to use the GroceryItem class above
a. Read a grocery
item from standard input (std::cin) until end of file. For each item
read:
i. Store the item in a dynamically allocated object
ii. Store the pointer to the item in a standard vector
b. After you have reached the end of file, write the grocery items to standard output (std::cout) in reverse order.
c. Be sure to release the
dynamically allocated objects before exiting the program
I tried looking at multiple forums and can't figure out how to print my vector forwards or backwards since it is a pointer to an object. I'm confused on how to print each member within the object
#include <iostream>
#include "GroceryItem.hpp"
#include <vector>
#include <string>
int main()
{
// vector of GroceryItem pointer
std::vector<GroceryItem*> groceries;
// variables for the parameter of the constructor
std::string upc;
std::string brand;
std::string product;
double price;
int size;
std::cout << "How many grocery items are in your list: ",
std::cin >> size; // size of vector
for (int i = 0; i < size; i++)
{
std::cout << "UPC: ", std::cin >> upc;
std::cout << "Brand Name: ", std::cin >> brand;
std::cout << "Product Name: ", std::cin >> product;
std::cout << "Price: ", std::cin >> price;
// constructor of GroceryItem object
groceries.push_back(new GroceryItem(upc, brand, product, price));
}
// trying to print the vector backwards but it only prints the
// address (i want it to print each memeber of the object)
int iterator = size - 1;
while (iterator != -1)
{
std::cout << groceries[iterator] << "\n";
iterator--;
}
return 0;
}
//trying to print the vector backwards but it only prints the
//address (i want it to print each memeber of the object)
In that case, use:
std::cout << *(groceries[iterator]) << "\n";
However, to be able use that, you must add the following overload:
std::ostream& operator<<(std::ostream& out, GroceryItem const&);
I am creating a class that will keep track of students. In this class, I use an overloaded = to copy these student objects. To track their classes, I use a dynamic array. The array copies just fine; however, when clearing the variables of a student object, any object that had copied from it before also has their array wiped. Here is the code:
#include <iostream>
#include <string>
using namespace std;
class Student
{
string name; //Name
string* classList = NULL; //Empty array to store class names in
int numClasses = 0; //Number of classes
public:
void InputData()
{
cout << "Enter student name: " << endl; //Input Name
cin >> name;
cout << "Enter number of classes: " << endl; //Input classes
cin >> numClasses;
classList = new string[numClasses]; //Define array size
for (int i = 0; i < numClasses; i++) //For every spot in array, name class
{
cout << "Enter name of class " << (i + 1) << ":" << endl; //Name class
cin >> classList[i];
}
};
void OutputData()
{
cout << "Name: " << name << endl; //Output data
cout << "Number of Classes: " << numClasses << endl;
for (int i = 0; i < numClasses; i++) //Cycle through and output classes
{
cout << "Class " << i << ": " << classList[i] << endl;
}
};
void ResetClasses()
{
name = "";
delete[] classList; //Free Memory
classList = NULL; //Clear array
numClasses = 0;
};
Student operator =(Student& student) //Overload =
{
this->name = student.name;
this->classList = student.classList;
this->numClasses = student.numClasses;
return *this;
};
};
int main()
{
Student s1, s2;
s1.InputData(); // Input data for student 1
cout << "Student 1's data:" << endl;
s1.OutputData(); // Output data for student 1
s2 = s1;
cout << "Student 2's data after assignment from student 1:" << endl;
s2.OutputData(); // Should output same data as for student 1
s1.ResetClasses();
cout << "Student 1's data after reset:" << endl;
s1.OutputData(); // Should have no classes
cout << "Student 2's data, should still have original classes:" << endl;
s2.OutputData(); // Should still have original classes
}
The main offenders almost certainly being either of these two
void ResetClasses()
{
name = "";
delete[] classList; //Free Memory
classList = NULL; //Clear array
numClasses = 0;
};
Student operator =(Student& student) //Overload =
{
this->name = student.name;
this->classList = student.classList;
this->numClasses = student.numClasses;
return *this;
};
The output for a program is:
Enter student name:
ERIC
Enter number of classes:
2
Enter name of class 1:
C++
Enter name of class 2:
C
Student 1's data:
Name: ERIC
Number of Classes: 2
Class 0: C++
Class 1: C
Student 2's data after assignment from student 1:
Name: ERIC
Number of Classes: 2
Class 0: C++
Class 1: C
Student 1's data after reset:
Name:
Number of Classes: 0
Student 2's data, should still have original classes:
Name: ERIC
Number of Classes: 2
Class 0:
Class 1:
What could I be doing wrong to cause this?
Student operator =(Student& student)
The assignment operator should take a const reference parameter. The assignment operator should also return a reference, and not a value.
This class is also missing a copy constructor.
In the assignment operator:
this->classList = student.classList;
This is a plain pointer. For starters, this is a memory leak. The previous pointer (if there is one) gets lost, and its allocated memory gets leaked.
Now you have two instances of your class with the same classList pointer. Consequently, when the resetClasses() method gets called on one of those classes, it'll be deleted, and since the other instance of the class has the same pointer, it's now pointing to deleted memory.
Your assignment operator must properly delete the existing array, if there is one, and clone the array held in the instance being assigned from, if there is one. Most of this would also apply to the copy constructor that you must implement.
This class is also missing a destructor, which will cause another memory leak.
You have all of these multiple fundamental problems with your class. You must fix all of them in order for your class to work correctly. You must implement a proper copy constructor, assignment operator, and destructor, that correctly clone, copy, and destroy instances of the data held by your class.
It appears that you haven't yet learned how to use containers and smart pointers, and the point of your excersize if for you to learn how to properly keep track of allocated memory, avoid memory corruption and memory leaks. That is obviously an important skill to learn; but once you've figured all of this out, and your class works correctly, you'll simply replace your pointers by a std::vector, and not worry about it any more.
You need to create a copy of the class list, or both student objects will have a field that points to the same location in memory.
Freeing one of these fields will cause the other one to also be freed.
In your copy constructor and assignment operator, create a new array of the same size for the new object, and then copy each of the elements to the new object.