windows causing breaking point - c++

I am writing a program for a class assignment on learning about pointers and memory management. Allocating memory for student and courses is necessary with the new operator in this assignment and the program seems to run properly but after it prints everything the program crashes and it says that that it has triggered a break point. Any help would be appreciated.
The error is located here but I'm not sure what it means
/* verify block type */
_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));
#include <iostream>
#include <string>
#include <iomanip>
using namespace std;
struct Student //Structs
{
string firstName, lastName, aNumber;
double GPA;
};
struct Course
{
int courseNumber, creditHours;
string courseName;
char grade;
};
Student* readStudent(); // Function Prototypes
Course* readCourseArray(int&);
void computeGPA(Student *student, Course *courseArray, int coursesTaken);
void printSummary(Student *studentPTR, Course *courseArray, int courses);
int main() //Main
{
int courses = 0;
Student *studentPTR = readStudent();
Course *coursePTR = readCourseArray(courses);
computeGPA(studentPTR, coursePTR, courses);
printSummary(studentPTR, coursePTR, courses);
delete studentPTR;
delete coursePTR;
system ("pause");
return 0;
}
Student* readStudent() // Read Student
{
Student* student = new Student;
cout<<"\nEnter students first name\n";
cin>>student->firstName;
cout<<"\nEnter students last name\n";
cin>>student->lastName;
cout<<"\nEnter students A-Number\n";
cin>>student->aNumber;
return student;
}
Course* readCourseArray(int &courses) //Read Courses
{
cout<<"\nHow many courses is the student taking?\n";
cin>>courses;
const int *sizePTR = &courses;
Course *coursePTR = new Course[*sizePTR];
for(int count = 0; count < *sizePTR; count++) //Enter course information
{
cout<<"\nEnter student "<<count+1<<"'s course name\n";
cin>>coursePTR[count].courseName;
cout<<"\nEnter student "<<count+1<<"'s course number\n";
cin>>coursePTR[count].courseNumber;
cout<<"\nEnter student "<<count+1<<"'s credit hours\n";
cin>>coursePTR[count].creditHours;
cout<<"\nEnter student "<<count+1<<"'s grade\n";
cin>>coursePTR[count].grade;
}
return coursePTR;
}
void computeGPA(Student *studentPTR, Course *courseArray, int coursesTaken) // Compute GPA
{
double total = 0, hours = 0;
for(int count = 0; count < coursesTaken; count++)
{
hours += courseArray[count].creditHours;
if (courseArray[count].grade == 'A')
total+=4;
else if (courseArray[count].grade == 'B')
total+=3;
else if (courseArray[count].grade == 'C')
total+=2;
else if (courseArray[count].grade == 'D')
total+=1;
else if (courseArray[count].grade == 'F')
total+=0;
}
studentPTR->GPA = (total / hours);
}
void printSummary(Student *studentPTR, Course *courseArray, int courses)
{
cout<<"\nReport\n";
cout<<"\nNumber Name Hours Letter Grade Point Grade";
cout<<"\n------ ---- ----- ------------ -----------\n";
for(int count = 0; count < courses; count++)
cout<<setw(3)<<courseArray[count].courseNumber<<" "<<courseArray[count].courseName<<setw(20)<<" "<<courseArray[count].creditHours<<setw(5)<<" "<<courseArray[count].grade<<endl;
cout<<"\nStudent :"<<studentPTR->firstName<<" "<<studentPTR->lastName;
cout<<"\nA-Number :"<<studentPTR->aNumber;
cout<<"\nOverall GPA :"<<studentPTR->GPA;
}

You're allocating courses with operator new[] (which is for arrays), but freeing it with operator delete, instead of operator delete[].
You should deallocate it like that:
delete[] coursePTR;
I also don't understand why you use the sizePTR pointer instead of directly using courses.
BTW, just so you'd know, this is not a 'find my bug' site. You have a code review site for that.

You need to change
delete coursePTR;
to
delete [] coursePTR;
new always needs to be used with delete, and new [] with delete [], otherwise bad things happen.

Related

Program crashes upon calling member function of an object pointer

As the title says, whenever I try to call a getter function to return the value of a private variable in an object pointer that is in a vector, it crashes. This causes my 2 other functions useless.
I know command == display and command == summary are not working properly. I did some debugging and found out that whenever I try to cout<<P_obj[i]->getnumber() for example, I crash.
Here is my code:
#include <string>
#include <cstdlib>
#include <fstream>
#include <iomanip>
#include <sstream>
#include <cstring>
#include <vector>
#include <cstdio>
using namespace std;
class stock {
private:
int sharenumber;
float shareprice;
string sharename;
public:
stock(int x, string y,float z)
:sharenumber(x),sharename(y),shareprice(z)
{
}
int returnnumber(){
return sharenumber;
}
string returnname(){
return sharename;
}
float returnprice(){
return shareprice;
}
};
bool ispositive(int x){
bool a = false;
if (x>0){a = true;}
return a;
}
void buy(vector <stock*> list,int size){
int amount;
float price;
string symbol;
cout<<"Please enter the number of shares, the share symbol and the price of the share to make your purchase.\n";
do{
cout<<"Enter the amount: ";
cin>>amount;
if (ispositive(amount)==false){
cout<<"Please enter a positive number for the amount!\n";
}
}while(ispositive(amount)==false);
cout<<"Enter the symbol: ";
cin>>symbol;
do{
cout<<"Enter the stock price: $ ";
cin>>price;
if (ispositive(price)==false){
cout<<"Please enter a positive number for the price!\n";
}
}while(ispositive(price)==false);
list.push_back(new stock(amount,symbol,price));
cout<<"Your purchase has been made. Thank you for your time.\n\n";
}
void summary(vector <stock*> list,int size){
float cost = 0;
int stocktotal = 0;
for (int i = 0; i < size;i++){
cost = cost + (list[i]->returnprice()*list[i]->returnnumber());
stocktotal = stocktotal + list[i]->returnnumber();
}
cout<<"\nUser has made "<<size<<" purchases in total. The total number of stocks bought is "<<stocktotal<<". The total cost is "<<cost<<"."<<endl<<endl;
}
int main(int argc, char *argv[])
{
vector <stock*> P_obj;
bool cont = true;
bool last_cont = true;
char * check;
bool signal = false;
string command;
char done;
if (argc>1){
check = strstr(argv[1],".txt");
if (check!= NULL){
fstream tester;
tester.open(argv[1]);
if (tester.is_open()){
signal=true;}
}else{cout<<"Error has occurred. Please enter correct data file name with .txt extension.";}
if (signal){
cout<<"\nWelcome to the Golden Sacks! Enter a command to start your stock trading career.\n\n";
ofstream user_data(argv[1]);
while(cont==true){
bool e_valid = false;
cout<<"Enter command here: ";
cin>>command;
if (command == "buy"){
buy(P_obj,P_obj.size());
}
if (command == "summary"){
summary(P_obj,P_obj.size());
}
if (command == "display"){
cout<<"\nList of all purchases:\n";
for (int y = 0; y < P_obj.size(); y++){
cout<<P_obj[y]->returnnumber()<<" "<<P_obj[y]->returnname()<<" "<<"$"<<fixed<<setprecision(2)<<P_obj[y]->returnprice()<<endl;
}
cout<<endl;
}
if (command=="help"){
cout<<"Command list:\n";
cout<<left<<setw(2)<<"- buy\n";
cout<<left<<setw(2)<<"- display\n";
cout<<left<<setw(2)<<"- summary\n";
cout<<left<<setw(2)<<"- find <stock-symbol>\n";
cout<<left<<setw(2)<<"- amount>= <purchase-amount>\n";
cout<<left<<setw(2)<<"- help\n";
cout<<left<<setw(2)<<"- exit\n\n\n";
}
if (command == "exit"){
while (last_cont == true){
cout<<"Are you sure you want to quit? (Yy/Nn):";
cin>>done;
if (done == 'Y'||done == 'y'||done =='N'||done =='n'){
last_cont=false;
if(done=='Y'||done=='y'){
cont = false;
cout<<"Thank you for using Golden Sacks. We hope to see you soon!\n";
}
}else {cout<<"Please enter only Y|N or y|n, try again.\n\n";}
}
}
} //end of loop
for (int i = 0; i < P_obj.size(); i++){
user_data<<P_obj[i]->returnnumber()<<" "<<P_obj[i]->returnname()<<" "<<"$"<<fixed<<setprecision(2)<<P_obj[i]->returnprice()<<endl;
}
}
}else {cout<<"Too few arguments, enter a data file name with .txt extension to continue";}
}
vector <stock*> P_obj;
is not properly allocated. //memory leak
stock is not a user defined type like int or double.
so if you are using it as a pointer, use RAII technique with it, deallocate it in it's destructure
eg:
class Stock{
int* x{nullptr};
public:
Stock(...);//allocated here
~Stock(..);//deallocate here
};
you can further more defined new and delete operators

Segmentation fault with dynamically allocated arrays as members of structure in c++?

I am writing a program using an array of structures to store a name, id number, and an array of test scores for a certain amount of students. Both the array of structures and the array of test scores member need to be dynamically allocated. I've gotten down to the function that allows the user to input test scores for each student, however I am having problems with the cin in the last function (getScores function). When using Linux I get a segmentation fault, so I'm assuming it has something to do with the dynamically allocated tests array that is a member of the structure, I just can't see it. I'm wondering how I can go about debugging it and an explanation of why this is actually occurring so I can avoid it in the future.
//Preprocessor Directives
#include <iostream>
#include <iomanip>
#include <string>
using namespace std;
//Structure declaration
struct Students
{
string name; //Student name
int idNum; //Student ID number
double *tests; //Pointer to an array of test scores
};
//Function prototypes
Students *getStudents(int &);
double *getTests(int &);
void getInfo(string &, int &, int);
void getScores(double &, string, int);
//Main program section
int main ()
{
int numStudents = 0;
int numTests = 0;
Students *studentFiles = NULL;
//Call the getStudents function
studentFiles = getStudents(numStudents);
//Call the getTests function
studentFiles->tests = getTests(numTests);
for(int i = 0; i < numStudents; i++)
{
//Call the getInfo function
getInfo(studentFiles[i].name, studentFiles[i].idNum, i+1);
}
for(int i = 0; i < numStudents; i++)
{
for(int j = 0; j < numTests; j++)
{
getScores(studentFiles[i].tests[j], studentFiles[i].name, j);
}
}
delete [] studentFiles;
delete [] studentFiels->tests;
return 0;
}
Students *getStudents(int &numStudents)
{
Students *studentFiles = NULL;
//Prompt the user for the number of students
cout<<"Enter the number of students: ";
cin>>numStudents;
//Dynamically allocate an array of structs, one for each student
studentFiles = new Students[numStudents];
return studentFiles;
}
double *getTests(int &numTests)
{
double *tests = NULL;
//Prompt the user for the number of tests
cout<<"Enter the number of tests: ";
cin>>numTests;
cin.ignore();
//Dynamicall allocate an array of integers, one for each test
tests = new double[numTests];
return tests;
}
void getInfo(string &name, int &idNum, int index)
{
//Prompt for each student's name and id number
cout<<"Enter the name of student #"<<index<<": ";
getline(cin, name);
cout<<"Enter the id number of student #"<<index<<": ";
cin>>idNum;
cin.ignore();
}
void getScores(double &test, string name, int numTest)
{
cout<<name<<endl;
cout<<numTest<<endl;
//Prompt for each test score for each student
cout<<"Enter "<<name<<"'s score for test #"<<numTest+1<<": ";
cin>>test;
}
One error is that you access a member of deleted object studentFiles. Reverse the lines to fix that:
delete [] studentFiles->tests;
delete [] studentFiles;
Ideally, use std::vector<> instead of dynamically allocating and releasing memory manually.
Also note, that the code only initializes Student::tests of the first member of the array, the rest of Student objects have this member uninitialized. The result of expression studentFiles[i].tests[j] is undefined and is likely to cause a crash.
You need to initialize Student::tests member of each Student. And when done, deallocate Student::tests of each Student.

How to clear memory allocated for an array that's pointed to by a pointer correctly in C++?

Before you read my code, I want everyone to know that I am not using my code anywhere which is why it doesn't have much comments. It's just an example I wrote up to ask this question and it works the way I want it to. Feel free to try it out.
I have a question about my delete function. Does delete[] pTemp->top3Grades; actually delete/free all the array items? Does it know to stop after 3 elements? How? What if some data is right next to in memory which could be the same data (or same type of data) as the first 3? Is 3 passed secretly into the delete function so it knows when to stop? Or does it just delete pTemp->top3Grades[0], the first element?
And if possible, how would I check if it was deleted? I use XCode which come with a debugger if it helps.
#include <iostream>
using namespace std;
struct Students{
int idNum;
int age;
Students* pNext;
int* top3Grades;
};
void deleteAllStudents(Students* *head){
Students* pTemp = *head;
while (pTemp!=NULL) {
*head = pTemp->pNext;
delete[] pTemp->top3Grades; //Does this eliminate all 3 elments
//or just the first? How would you
//check if it is?
delete (pTemp); //Might as well ask...how I can see
//this was deleted/freed up?
pTemp=*head;
}
}
void addStudent(Students* *head, int id, int age, int grade1, int grade2, int grade3){
Students* studentEntry= new Students;
studentEntry->top3Grades= new int[3]; // Yes I could have set this as static when
// defining it in struct up above, but
// this way is related to my question later
studentEntry->top3Grades[0] = grade1;
studentEntry->top3Grades[1] = grade2;
studentEntry->top3Grades[2] = grade3;
studentEntry-> idNum = id;
studentEntry-> age = age;
studentEntry->pNext=NULL;
Students* pTemp;
pTemp = *head;
if (*head==NULL) {
*head = studentEntry;
} else{
while (pTemp->pNext!=NULL) {
pTemp= pTemp->pNext;
}
pTemp-> pNext= studentEntry;
}
}
void dispalyAllStudents(Students* *head){
Students* pTemp;
pTemp = *head;
while (pTemp!=NULL) {
cout<<"ID #: "<<pTemp->idNum<<" Age: "<<pTemp->age<<endl;
cout<<"Best grades are "
<<pTemp->top3Grades[0]<<" "
<<pTemp->top3Grades[1]<<" "
<<pTemp->top3Grades[2]
<<endl<<endl;
pTemp= pTemp->pNext;
}
}
int main()
{
int inputNum, studentID, studentAge, bestGrade1, bestGrade2, bestGrade3;
Students* pHead=NULL;
cout<< "How many records do you want to input? ";
cin >> inputNum;
for (int i = 0; i<inputNum; i++) {
cout<<endl;
cout<<"Enter ID Number: ";
cin>>studentID;
cout<<"Enter age: ";
cin>>studentAge;
cout<<"Enter first best grade: ";
cin>>bestGrade1;
cout<<"Enter second best grade: ";
cin>>bestGrade2;
cout<<"Enter third best grade: ";
cin>>bestGrade3;
addStudent(&pHead, studentID, studentAge, bestGrade1, bestGrade2, bestGrade3);
}
cout<< "--------"<<endl;
dispalyAllStudents(&pHead);
deleteAllStudents(&pHead);
return 0;
}
Yes, delete[] knows how many elements there are if you pass it a pointer that was returned from a call of new[]. In your code, you have essentially:
int * p = new int[3];
// ...
delete [] p;
That's exactly what it is designed to do.
How does it do that? That's not really your business. As for the present example, in the quasi-standard Itanium ABI for C++, there is nothing to do, and you essentially end up with a call of free() on the underlying memory. (So just use your existing understanding of free() to fill in the blanks.) If the type of the array element was not trivially destructible, the compiler would need to store the number of array elements somewhere in some "hidden" place (which the Itanium ABI specifies) so that it can call all the destructors.

c++ dynamic classes without using vector

So I happened to finish my homework program but today during lecture my good ol professor told us we are not allowed to use STL as in vectors or list to create our database. We were also told we need all our variables private. I was doing this program completely wrong. This is what I have so far.
in class.h
class Student {
private:
string last;
string first;
int student_id;
int enroll_id;
int *grades;
}
class Gradebook {
public:
Gradebook();
void newCourse(Gradebook *info);
private:
string name;
int course_id;
int count_course;
int enroll;
Student *students;
public:
//Constructor
}
I know I can access private members of Gradebook by using a constructor so I can set every member in my Gradebook.
function to create a newCourse
Gradebook::Gradebook() {
students = new Student;
course_id=0;
count_course=0;
enroll = 0;
}
Gradebook::newCourse(Gradebook *info) {
int i, loop=0;
cout << "Enter Number of Courses: ";
cin >> loop;
info = new Gradebook[loop];
for(i=0; i<loop; i++) {
cout << "Enter Course ID: ";
cin >> info[info->count_course].course_id;
cout << "Enter Course Name: ";
cin >> info[info->count_course].name;
info->count_course++
}
}
So Courses are now sets. Since the variables in Student are private. I can't just use a pointer to the variables to access them. Can someone show me how to do this?
Ok I didnt know how to ask this question but I actually answered it. But I want everyones opinion on my method.
class Student {
public:
void setID(int ID){student_id = ID; };
int getID(){return student_id);
private:
string last;
string first;
int student_id;
int enroll_id;
int *grades;
};
class Gradebook {
public:
Gradebook();
void newCourse(Gradebook *info);
void newStudent(Gradebook *info);
private:
string name;
int course_id;
int count_course;
int count_student;
int enroll;
Student *students;
public:
//Constructor
}
void Gradebook::newStudent() {
int i, loop=0;
int student=0;
string lastName;
cout << "Enter number of students: ";
cin >> loop;
for(i=0; i<loop; i++) {
cout << "Enter Student ID: ";
cin >> student;
info->students[info->count_student].setID(student);
cout << "Enter Last Name: ";
cin >> lastName;
info->students[info->count_student].setLast(lastName);
info->count_student++;
}
}
Is there anything wrong of doing it this way?
edit: You can't use 'Student *students' for your container for multiple Students...
You could use your own lists. Something like
struct Participant{ // or class (and maybe more clever name)
Student *student;
Participant *prev;
Participant *next;
};
You have to do little pointer-acrobatics, but maybe that's the idea for this exercise..
And like in previous answer, use get and set functions in your Student class.
Ok, I'm sorry but your code is a mess...
I can't do this homework for you, but here is few tips that came in mind
Are you sure that it wouldn't be easier to make different classes for Student, Course and Gradebook? I don't know your homework specifications, so I can't be sure what it is that your program should actually do.
You can not use int *grades to store all of one students grades. Same goes for Student *students. You can not access iterate *students like an array students[i].something()
If you use some help class(or struct) like Participant, you have to find right student by iterating in loop. Notice, that you have store 'first' participant inside your class and 'int students' keep in your student count (also inside your class)
Participant *current = first;
int id = Id; // Id is from function/method call
for(unsigned int i = 0; i < students; ++i){
if(current->getId()== id){
// do something and
break;
}
else if(current->next != NULL){ // test this just in case
current = current->next;
}
else break; // something went wrong
}
It might be good idea to store all students in one list (that you make) and use pointers in Course or in Gradebook or where ever... If you know 'static' here is a hint
class Student{
public:
. // get and set functions
static Student* getStudent(int id); // return NULL if no student with id
private:
static Student *first;
static Student *last;
static unsigned int counter; // helps with loops, but you can always use next != NULL
Student *next;
Student *prev;
}
Put this inside the Student constructor
with first student that you create you set first and last to point him/her, and next and prev to NULL. After that, always when you create a new student you set
this->prev = last;
last->next = this;
last = this;
this->next = NULL;
Do not implement program logic inside class. Do it in main() or in some other function, but i think main() is fine for now. If you need to add new student in gradebook, ask all the necessary info in main() and make some function like Gradebook::newStudent(int &Id, string &last_name){ // store student info in gradebook }
Usually these homework programming exercises don't have be too fancy or streamlined or fully optimized. So don't overdo them ;)
class Student {
private:
string last;
string first;
int student_id;
int enroll_id;
int *grades;
public:
string &getLast(){ return Last; }
...
...
};
Call Student::getLast() when you need to access your last variable etc
or
void setLast(string sLast){last = sLast;} for writing and
string getLast(){return last;} for reading
And example of dynamic array:
struct Student;
int Count = 0;
Student *Students = nullptr;
int AddStudent(Student nStudent)
{
Student *Buffer = new Student[Count + 1];
for (int a = 0; a < Count; a++)
Buffer[a] = Student[a];
Buffer[Count] = nStudent;
if(Students)
delete[] Students;
Students = Buffer;
return ++Count -1
}
void RemoveStudent(int Index)
{
Student *Buffer = new Student[Count - 1];
for (int a = 0; a < Index; a++)
Buffer[a] = Students[a];
for (int a = Index; Index < Count - 1; a++)
Buffer[a] = Students[a - 1];
if (Students)
delete[] Students;
Students = Buffer;
}

How to create a pointer to pointer array to struct?

I want to create a dynamic array of pointers that each one of them points to a struct. In the program there is an option to add structs and if the counter reaches the last the value of the array, the array expands.
struct student
{
string id;
string name;
};
int N=5;
int counter=0;
student **big=new student *[N]; //a ptr to an array of ptr's.
void add_student (int &counter,student **big)
{
int i;
if (counter==0)
{
for (i=0; i<N; i++)
{
big[i]=new student;
}
}
if (counter==N)
{
N+=5;
student **temp=new student *[N];
for (i=counter-1; i<N; i++)
{
temp[i]=new student;
}
for (i=0; i<counter; i++)
{
temp[i]=big[i];
}
delete [] big;
big=temp;
}
cout<<"Enter student ID: "<<endl;
cin>>(*big)[counter].id;
cout<<"Enter student name: "<<endl;
cin>>(*big)[counter].name;
counter++;
}
When I run the program it crashes after I try to add more than one student. Thanks!
Try this code. Main problem was that you write to (*big)[counter].id without this being valid memory. In my function below a student object is created first, then writen to.
PS: I have not tested the code, let me know if it has problems with it.
struct student {
string id;
string name;
};
int N=5;
int counter=0;
student **big = new student *[N]; //a ptr to an array of ptr's.
// Variable big and counter is global, no need to pass as argument.
void add_student (student *new_student) {
// Resize if needed
if (counter==N) {
int i;
student **temp=new student *[N+5];
// Copy from the old array to the new
for (i=0; i<N; i++) {
temp[i]=big[i];
}
// Increase maximum size
N+=5;
// Delete the old
delete [] big;
big=temp;
}
// Add the new student
big[counter] = new_student;
counter++;
}
// Function called when we should read a student
void read_student() {
student *new_student = new student;
cout<<"Enter student ID: "<<endl;
cin>>new_student->id;
cout<<"Enter student name: "<<endl;
cin>>new_student->name;
// Call the add function
add_student (new_student);
}
I just tried. the error is because you are not handling pointer to pointer to a struct correctly. to pass a pointer to pointer to something means the function can change the pointer address not only the thing it points to. so declaring a pointer to pointer in function is okay but declaring a global p to p to s doesn't make much sense. You can achieve the same effect using &ptr. for p to p to s i.e. pass the address of pointer to function. I made some changes but I'm not sure if it works. I will try again after 4/5 hours and will check the issue in detail. for the time being please content yourself with the following. (might be some errors below so be careful)
struct student
{
string id;
string name;
};
int N=5;
int counter=0;
student *big=new student[N]; //a ptr to an array of ptr's.
void add_student (int &counter,student **ppBig)
{
int i;
if (counter==0)
{
for (i=0; i<N; i++)
*ppBig[i]=new student;
}
if (counter==N)
{
N+=5;
student *temp=new student [N];
for (i=counter-1; i<N; i++)
temp[i]=new student;
for (i=0; i<counter; i++)
temp[i]=*ppBig[i];
delete[] *ppBig;
ppBig=temp;
}
cout<<"Enter student ID: "<<endl;
cin>>(*big)[counter].id;
cout<<"Enter student name: "<<endl;
cin>>(*big)[counter].name;
counter++;
}