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.
Related
I am trying to dynamically allocate an array and whenever it gets to the part where it dynamically allocates the program exits. I would rather not use vectors as I am trying to learn how to do this using dynamic arrays.
This is the simplified code:
#include <iostream>
#include <string>
using namespace std;
class Student
{
private:
double calcAverage(double* testArray);
char calcGrade(double average);
public:
int nTests, sameTests, idNum;
string name;
double average, *testArray;
char grade;
};
int i;
Student fillStudentArray(int nStudents);
int main()
{
*studentArray = fillStudentArray(nStudents);
return 0;
}
Student fillStudentArray(int nStudents)
{
Student *newStudentArray = new Student[nStudents];
cout << "If you can see this I worked. ";
delete[] studentArray;
return *newStudentArray;
}
I have tried the solution posted here Creation of Dynamic Array of Dynamic Objects in C++ but it also exits in a similar way. The main for the code looks like this.
int main()
{
int nStudents = 3; //this number is just for testing, in actual code it has user input
Student** studentArray = new Student*[nStudents];
cout << "1 ";
for(i = 0; i < nStudents; i++)
{
cout << "2 ";
studentArray[i] = new Student[25];
cout << "3 ";
}
return 0;
}
close (heres a cigar anyway)
Student* fillStudentArray(int nStudents); <<== function must return pointer to students
int main()
{
int nStudents = 3; <<<=== declared nstudents
Student *studentArray = fillStudentArray(nStudents); <<< declare studentArray
return 0;
}
Student *fillStudentArray(int nStudents) <<<== return pointer
{
Student* newStudentArray = new Student[nStudents];
cout << "If you can see this I worked. ";
// delete[] studentArray; <<<== what were you trying to delete?
return newStudentArray; <<<=== return pointer
}
the second code you showed is not relevant, its creating a 2d array
I'm having trouble with one of my assignments (or maybe I'm overthinking it?)
I need to create
a function to take integer parameters for number of students and tests.
Allocate the memory needed for the array of students and the array of test scores for each student.
Return a pointer to the array of Student structures. No display output is done in this function.
int main()
{
int studentNum;
int testNum;
cout << "How many students are there?\n";
cin >> studentNum;
cout << "How many tests are there?";
cin >> testNum;
system("pause");
return 0;
}
my function
GradeBook *initArrays(int s, int t)
{
GradeBook *ptr;
// Allocate the array of Student structures.
ptr = new GradeBook[s];
// Allocate an array of ints (to hold test scores)
// for each element of the array of Student structures.
for (int count = 0; count < s; count++)
{
ptr[count].tests = new int[t];
}
// Return a pointer to the array of structures.
return ptr;
}
edit: I have edited my function, could i get some opinions on that?
if you are writing this in c++, use classes. if i understand correctly, you should create a structure to save a students id,name,or something and a corresponding grade?
something like:
class Test{
public:
int id;
int grade;
Test(int id, int grade){
this->id = id;
this->grade = grade;
}
};
class Student{
public:
int id;
std::string name;
std::vector<Test> tests;
Student(int id, std::string name)
{
this->id = id;
this->name = name;
}
};
int main(){
vector<Student> students;
int studentnum;
for (int i = 0; i < studentnum; i++){
students.push_back(Student(i, "name"));
//insert all tests of the student by calling students[i].tests.push_back(Test(id, grade))
}
}
this way you don't have to allocate memory, which you can easily overlook freeing.
edit:
this is very basic and not a sophisticated solution, as the properties of the classes are all public.
edit 2:
typedef struct Test{
int id;
int grade;
}Test;
typedef struct Student{
int id;
std::string name;
Test * tests;
}Student;
int main(){
Student * students;
int studentnum;
students = (Student*)malloc(sizeof(Student)*studentnum);
for (int i = 0; i < studentnum; i++){
students[i]->id = id;
students[i]->name = "name";
student[i]->tests = (Test*)malloc(sizeof(Test)*numberofgradesofthatstudent);
for (int j = 0; j < numberofgradesofthatstudent; j++)
{
students[i]->tests[j]->id = testid;
students[i]->tests[j]->grade = grade;
}
}
}
this is schematic! new and malloc reserve memory on the heap, do not forget to free everything when you are done with it.
As said a little above, be careful using brackets {} to delimit your blocks.
Secondly,the syntax:
array[studIndex].Tests
supposes that the value array[studIndex] (here an integer) has a member value named Tests. But in this case it doesn't.
Think about your problem: you need to store two values "connected" to one another in a static array. The way I see it, you should try on with two dimensional arrays:
int 2dArray[nbStudents][nbTests];
If you don't want to bother with 2dimensional arrays, you can also try
int 2dArray[nbStudents * nbTests];
But for conveniance, it is often better to use 2d arrays.
Also, think about declaring your array before the for loops in your function.
Then concatenate two for loops as you did and I'll let you think about the rest...
I am doing a c++ book question and got stucked on this specific parts where it says
"write program that asks how many score there are and how many student there are. it should then dynamically allocate an array of structures, each structure's Test member should point to a dynamically allocated array that will hold the test scores,after array has been dynamically allocated the program should ask for the id number and test score for each student".
right now I have a problem in the for loop where there is a memory leak and program crashes after input values, any suggestions ?
here is the code:
struct Course
{
string Name;
int IdNumber;
int *Tests;
int Average;
int courseGrade;
};
void Result(int,int );
int main()
{
cout<<"please enter number of test score ";
int testScore;
cin>>testScore;
int numberofStudents;
cout<<"please enter number of student there is ";
cin>>numberofStudents;
Result(numberofStudents,testScore);
}
void Result(int numberofStudents,int testScore)
{
const int Size=numberofStudents;
const int Size1=testScore;
Course *object=nullptr;
object=new Course[numberofStudents];
object->Tests = new int[testScore];
for(int i=0;i<testScore;i++)
{
cin>>object[i].Tests[i];
}
}
here is the input on the console
please enter number of the test scores :3
please enter number of students there is :3
34
90
the program crashes after I input 90
Here's what I suspect is happening:
In this for loop:
for(int i=0;i<testScore;i++)
{
cin>>object[i].Tests[i];
}
You access object using testScore as an index. If testScore is larger than the length of object you will run into issues.
The memory leak problem comes from the fact that you are allocating space for object and every Tests member of a Course but you never free that memory.
There is a memory leak because you are allocating things withj new and never freeing them with delete.
As for the crash, it's being caused by this line:
object->Tests = new int[testScore];
Remember that object isn't a Course object, it's an array of Course objects, every one of which needs it's own Tests array. The line is effectively just object[0].Tests = ...
So You need a loop on numberofStudentsto allocate the test in each Course, and the another loop on numberofStudents around the loop on testScore (which you already have) to gather all the grades. (Advanced study: you can combine those two loops)
I have made some changes in your code, and it doesn't crash anymore. Why you need to use pointer of Test. I think it is good to use static memory instead of dynamic memory. Please check this
#include<iostream>
#include<cstring>
using namespace std;
struct Course
{
string Name;
int IdNumber;
int Tests[100];
int Average;
int courseGrade;
};
void Result(int,int );
int main()
{
cout<<"please enter number of test score ";
int testScore;
cin>>testScore;
int numberofStudents;
cout<<"please enter number of student there is ";
cin>>numberofStudents;
Result(numberofStudents,testScore);
}
void Result(int numberofStudents,int testScore)
{
const int Size=numberofStudents;
const int Size1=testScore;
Course *object=nullptr;
object=new Course[numberofStudents];
//object->Tests = new int[testScore];
for(int i=0;i<testScore;i++)
{
cin>>object[i].Tests[i];
}
}
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++;
}
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.