Create a structure that contains a pointer to an array - c++

I CAN NOT USE VECTORS FOR THE ASSIGNMENT
I have to create a structure that stores the following information: student name, id number, pointer to an array of test scores, average test score, letter grade.
The program should keep a list of test scores for a group of students. It should ask the user how many students are in the class and how many test scores there are.The number of test scores will be the same for every student. The program should dynamically allocate an array of structures. Each structures Tests member should point to a dynamically allocated array which will hold the test scores.
After the arrays have been dynamically allocated, the program should ask the user for the id number and all of the test scores for each student. The average score should be calculated and stored in the Average member of the structure. Display the student info.
I am having trouble when the user enters the test scores in the inputScores function. I can't figure out how to access the structure member right. Can you please look at my code and help me figure out what I'm doing wrong?
Here is my structure:
struct Grade
{
string name;
int idNum;
int* tests;
double average;
char grade;
};
Here are my functions:
//user enters number of students which is then used as the size of the dynamically allocated struct array
int inputStudents();
//user enters number of tests for each student which is then used as the size of the dynamically allocated array of test scores in the structure
int inputTests();
string inputName();
int inputID();
//user inputs scores for each student. this is a function i'm struggling with
int *inputScores(int *testScores, int numTests);
double calcAvg(int *testScores, int numTests);
char calcGrade(double);
void display(Grade*, int);
Here is my main:
int main()
{
Grade *studentList;
int size = inputStudents();
studentList = new Grade[size]; //dynamically create array of Grade struct
int numTests = inputTests(); //number of test scores stored in numTests
for (int i = 0; i < size; i++) //loop to store all student's info
{
studentList[i].name = inputName();
studentList[i].idNum = inputID();
studentList[i].tests = inputScores(studentList[i].tests, numTests, i);
studentList[i].average = calcAvg(studentList[i].tests, numTests);
studentList[i].grade = calcGrade(studentList[i].average);
}
display(studentList, size);
delete[] studentList;
return 0;
}
Here is the function i am struggling with. Every time I reference studentList a different error appears. My program won't even compile and I'm pretty sure this function is the reason why. Here I pass the tests structure member, rather than the entire structure. I also pass the number of tests and the counter from the loop in main that tells us which student the user is entering the test scores for.
int *inputScores(int *studentList, int numTests, int count)
{
cout << endl;
cout << "Enter the test scores:\n";
for (int i = 0; i < numTests; i++)
{
studentList[count].tests = new int[numTests]; //my error says the studentList must have a class type
cout << "Score " << (i + 1) << ": ";
cin >> studentList[count]->tests[i]; //my error says studentList must have a pointer type
cout << endl;
}
return studentList->tests; //my error says studentList must have a point-to-class type
}

You are passing a pointer to each student's test array to inputScores() but accessing it as a pointer to a student. You would have to change the inputScores() function as given below:
void inputScores(int *tests, int numTests, int count)
{
cout << endl;
cout << "Enter the test scores:\n";
for (int i = 0; i < numTests; i++)
{
cout << "Score " << (i + 1) << ": ";
cin >> tests[i];
cout << endl;
}
}
Also, I made one more modification. Its always better if the caller function allocates memory and pass a reference to the array. So we need to call the inputScores() function as given below
studentList[i].tests = new int[numTests];
inputScores(studentList[i].tests, numTests, i);
This is the output I received:
How many students are there?
3
How many tests does each student have?
2
Enter the student's name:
Joohn
Enter the student's ID number:
1
Enter the test scores:
Score 1: 12
Score 2: 13
Enter the student's name:
Jack
Enter the student's ID number:
2
Enter the test scores:
Score 1: 67
Score 2: 45
Enter the student's name:
Jill
Enter the student's ID number:
3
Enter the test scores:
Score 1: 56
Score 2: 89
--------------------------------------------------------
Here is all the info I have for each student:
Student #1:
Name: Joohn
ID Number: 1
Test Scores: Average Grade: 12
Letter Grade: F
Student #2:
Name: Jack
ID Number: 2
Test Scores: Average Grade: 56
Letter Grade: F
Student #3:
Name: Jill
ID Number: 3
Test Scores: Average Grade: 72
Letter Grade: C
--------------------------------------------------------

Your function inputScores is declared like this
int *inputScores(int *studentList, int numTests, int count)
which means studentList is a pointer to an int (which can be treated like an array). Later in the function, you attempt to do this:
studentList[count].tests = new int[numTests];
If studentList is an int* (or int array), then studentList[count] is just an int. You're trying to access the member variable tests of an int. But int is a primitive type.
When you called this function in main, you correctly passed an int*:
studentList[i].tests = inputScores(studentList[i].tests, numTests, i);
So treating the variable like it were actually an int * instead of a Grade * should solve the first of your problems. You should also change the name of the variable, since you're not really passing a studentList, it's more of a tests variable. That should help cut down on some of the confusion.
int *inputScores(int *tests, int numTests, int count)
After that, you'll realize that even through you're passing studentList[i].tests to your inputScores function, you'll have a memory leak and not be able to access the memory you thought you just filled. You DID fill memory, but when you tried to assign a new value to tests via tests = new int[numTests];, that only changed the local copy of tests.
To fix THAT problem, you need to pass tests by reference, like this:
int *inputScores(int*& tests, int numTests, int count)
That will allow any changes you make in your function to the int*, tests, to persist outside of the function.

Related

Increasing class pointer array

In my code, I want to add one student info into my class pointer array and the array size will increase each time a new student is added. Here is my code:
My header file:
class Student{
public:
int studentID;
char studentName[20];
int currentEnrollment;
Student();
void AddStudent(Student *tempStudent[], int countStudent, int sizeOfArray);}
My Class definition file:
void Student::AddStudent(Student *tempStudent[], int countStudent, int sizeOfArray)
{
for (int i = countStudent; i < sizeOfArray; i++)
{
cout << "Please enter student id (4 digits only): ";
cin >> tempStudent[i]->studentID;
cout << "Please enter student name: ";
cin >> tempStudent[i]->studentName;
}
}
My Main.cpp file
int *totalStudent = new int;
*totalStudent = 1;
int i, j, countStudent = 0;
int sizeOfArray = *totalStudent;
Student *newStudent[*totalStudent];
//Each time a new student is added, I will allocate a new memory for the array element, then add student Info using function.
for (i = countStudent; i < *totalStudent; i++)
{
newStudent[i] = new Student;
newStudent[i]->AddStudent(newStudent, countStudent, sizeOfArray);
countStudent++;
*totalStudent++;
}
When I run my code, I get an undefined reference error, so I do not know If I am able to increase my array or not. I intend to use C++ syntax so I use new and delete. Thank you for your help.
P.S: Here is my new code and it runs great, the only missing is the studentID for the first element in array.
In my main class:
int numStudent = 0;
int i, j, countStudent = 1;
Student *newStudent = new Student[countStudent];
AddStudent(newStudent, countStudent, numStudent);
My Student.h
class Student{
public:
int studentID;
char studentName[20];
int currentEnrollment;
};
Student AddStudent(Student *newStudent, int &countStudent, int &numStudent);
and My Student.cpp
Student AddStudent(Student *newStudent, int &countStudent, int &numStudent)
{
Student tempStudent;
cout << "Please enter student id (4 digits only): ";
cin >> tempStudent.studentID;
cout << "Please enter student name: ";
cin >> tempStudent.studentName;
newStudent[numStudent] = tempStudent;
numStudent++;
if (numStudent == countStudent)
{
Student *newStudentSize = new Student[countStudent + 1];
for (int i = 0; i < numStudent; i++)
{
newStudentSize[i] = newStudent[i];
}
delete []newStudent;
return *newStudentSize;
countStudent += 1;
}
}
Running this code will give me the following result:
StudentID: 11
StudentName: Dat
StudentID: 23
StudentName: Michael
Printing:
StudentID: 0
StudentName: Dat
StudentID: 23
StudentName: Michael
While it doesn't make sense to increase the array for each new student (it's inefficient) here's one way you can do it (I didn't even try to make your code compile because it has a number of issues and is unnecessarily complicated). Note that tempStudent (in the code snippet below) doesn't even have to be created using new. This solution stores Student objects in the students array (although it's easy to modify it to store Student object pointers instead). That said, usually, you'll just want to create an array of large enough size to accomodate all students (just set studentCount to some appropriate number and not 1 like in the example below).
class Student{
public:
int studentID;
char studentName[20];
int currentEnrollment;
Student(){};
};
int main(){
int studentCount=1;
Student * students = new Student[studentCount];
int numStudents=0;
bool done=false;
char finished='N';
while (!done){
//Student *tempStudent = new Student();
//create a Student on the stack
Student tempStudent;
cout << "Please enter student id (4 digits only): ";
//No input checking is done here
cin >> tempStudent.studentID;
No input checking is done here
cout << "Please enter student name: ";
cin >> tempStudent.studentName;
students[numStudents] = tempStudent;
numStudents++;
cout << "Stop entering students: Y or N";
cin >> finished;
done = finished=='Y' or finished=='y' ? true : false;
if(numStudents==studentCount){
students = ReallocateStudents(students, studentCount, studentCount*2);
studentCount *= 2;
}
}//end while
//print the students info
for(int i=0;i<numStudents;i++){
Student st = students[i];
cout << st.studentID << " " << st.studentName << std::endl;
}
//deallocate the students array or if you place this in the main like you did, the program will exit immediately so there's no need to deallocate
return 0;
}
Student * ReallocateStudents(Student* st, int oldSize, int newSize){
Student * newStudents = new Student[newSize];
//copy the existing values from the old array to the new one
for(int i=0;i<oldSize;i++){
newStudents[i] = st[i];
}
delete [] st; //delete the old array
return newStudents;
}
UPDATE:
Since you don't want to do everthing in the main(), just create a free AddStudents function and do everything there. Alternatively, you can create a
static function inside the Student class. It makes no sense to create AddStudent as a member of Student because that would require you to use an instance of Student to add a new instance, which makes for poor design (not to mention technical issues etc).
int main(){
// some code here
Students * allStudents = AddStudents();
//print students
}//end main
Students * AddStudents(){
int studentCount=1;
Student * students = new Student[studentCount];
int numStudents=0;
bool done=false;
char finished='N';
while (!done){
//create a Student on the stack
Student tempStudent;
cout << "Please enter student id (4 digits only): ";
//No input checking is done here
cin >> tempStudent.studentID;
No input checking is done here
cout << "Please enter student name: ";
cin >> tempStudent.studentName;
students[numStudents] = tempStudent;
numStudents++;
cout << "Stop entering students: Y or N";
cin >> finished;
done = finished=='Y' or finished=='y' ? true : false;
if(numStudents==studentCount){
students = ReallocateStudents(students, studentCount,
studentCount*2);
studentCount *= 2;
}
}//end while
return students;
}
This is simple and easy to both understand and maintain so I suggest using this approach.
addStudent does not do anything with the Student object it belongs to. So there is no need to put it in the 'Student' class. (Or you could rather rewrite it so it does something with the student object it belongs to). And it currently does not "add" anything, so the name is confusing.
What is technically wrong with it depends on what you want it to do. Currently it initializes student objects expected to already exist and pointed to by an array, from a specific array index, to the end of the array. That could well be a useful function, if that is what you want it to do. But you then must call it correctly with an array of pointers that point to valid Student objects, which you currently do not.
Currently in main you have a loop that initializes pointers in an array. And each time you initialize a pointer, you call AddStudent(..). The problem is that 'AddStudent()' tries to initialize ALL the student pointed to by your array.
This has two major problems (In addition to all the other problems with your loop).
Each time you create a new student, all your existing students will be
initialized again with new input from std::cin. (So for n students, you will
try to do n*n initializations)
While the loop in main is running, not all pointers in your array points
to existing Student objects. This may result in important data being
overwritten, a program crash or something totally different and unexpected.
You should sit back and reevaluate how you want to do things. Trying to fix single bugs in your existing code, one after another, will just create more bugs.
Just a hint to get you started:
class Student
{
public:
int studentID;
char studentName[20];
int currentEnrollment;
Student();
void init_from_cin();
};
And in your class definition file:
void Student::init_from_cin()
{
cout << "Please enter student id (4 digits only): ";
cin >> studentID;
cout << "Please enter student name: ";
cin >> studentName;
}
If you create a new Student like this:
Student *new_student = new Student;
new_student->init_from_cin();
Then after calling init_from_cin(), the Student object pointed to by new_student should be initialized.
How to create and initialize multiple Student objects in a loop, is left as exercise for the reader. But when you do it, you should understand what your lower and upper bounds of your loop are supposed to be. And you should also understand why moving the upper bound further away while your loop is running is a bad idea.
And never forget that sane programming languages start array indexing with 0.

How do I make my program pass data to my array correctly? (Homework)

I've set my array size to 20 (I set it to 19 assuming it's counting 0). I set my for loop to only run so long as gradeCount <= to gradeCounted yet it will keep running no matter how many times I enter data. If I enter 3 grades without pressing enter between each one, such as "23 23 23" it will return "Enter Grade" 3 times in a row, rather, for as many grades as I enter, separated by spaces. I don't understand why it's not passing data into the array and ending the for loop properly. I'm sure my code is an ugly mess, sorry.
Also, when entering code into stackoverflow, it said to indent the code 4 spaces to format? I couldn't initially indent the code with the code button and there was no {} button either. What am I missing? It was only after a notification to fix it that I was able to. Thanks for your time, I don't want to be a pain in the ass for you guys.
//This program asks user how many grades there are, inputs grades, and displays median of said grades.
#include <iostream>
using namespace std;
//Variables
////////////////////const int limitGrades = 20; //Array "boxes"? //Ignore this //for now.
int gradeCounted; //Number of grades from user.
const int SIZE = 19;
//Array
float grades[19]; //Max grades that can be entered.
//Functions
void gradeTaker()
{
cout << "You may input up to 20 grades. \n";
cout << "First enter the number of grades you have: \n";
cin >> gradeCounted;
//requests how many grades there are and stores them in array
for (int gradeCount = 0; gradeCount <= gradeCounted + 1; gradeCount++)
{
for (float &grade : grades)
{
cout << "Enter grade: \n";
cin >> grade;
}
}
};
int main()
{
gradeTaker();
cout << "grades so far";
for (int grade : grades)
cout << grade << endl;
system("pause");
}
The size of the array is separate from how you access it. Accessing 20 values is the equivalent to accessing indices from 0 to 19.
float grades[20];
for(size_t i = 0; i < 20; i++){ // print all values of grades
std::cout << grades[i] << "\n";
}
Furthermore, your for loop in gradeTaker will ask you for a value for each index of grades a total of gradeCounted + 2 times. To fix this, only iterate over the indices that you're assigning a value to like so:
for (int gradeCount = 0; gradeCount < gradeCounted; gradeCount++){
cout << "Enter grade: \n";
cin >> grade[gradeCount];
}
Finally... the for loop in your main function will iterate across the entire array which may include uninitialized values. You should initialize the array or use a dynamic data structure like std::vector and just push_back the necessary values.
(P.s. highlight code in the text-block and press CTRL+K to indent.)

Need help passing arrays, and input arrays

So this is a topic that is often confused, the arrays are always passed by reference.
The point of this program is to have a company figure out how much food their kittens are eating weekly.
So the program works well however whenever I go to send my food values ,,, that the use inputs themselves, (these are the amounts of food each kitten is eating weekly), its sending back values that arent what i'm trying to pass, theyre just random numbers in memories, and i assumed that its because im not returning a value, but i read that these values are passed by reference and that you do not need to return a value,
Please help!
#include <iostream>
using namespace std;
void kittyfood(string kittyNames[], int sizeOfArray); //prototype for kittyfood function
void report(string kittyNames[], int sizeOfArray, float food[]); //prototype for report function
int main()
{
string names[5]={"Fluffy","Sneaky","Moonie","Stuffy","Oriana"}; //set cat names to the array
float food[5]; //float array for food amounts with 5 elements
kittyfood(names,5); //call too kittyfood function passing the kitty names and the size of array
report(names,5,food); //call to report function with kitty names, size of array, and ammount of foods
return 0;
}
void kittyfood(string kittyNames[], int sizeOfArray)
{
float food[5];
for (int i=0;i<sizeOfArray; i++) //loop to go through cat names and get the amounts of food they eat
{
cout << "Please enter the amount of food in pounds "<< kittyNames[i] << " eats weekly\n"; //prompt user food eaten
cin >> food[i]; //user input food eaten
while (food[i]<0)
{
cout << "This cannot be a negative ammount \n"; //input validation
cin >> food[i];
}
}
}
void report(string kittyNames[], int sizeOfArray, float food[])
{
float smallest, largest; //declaration for the smallest and largest amount
string smallestName, largestName; //declaration for the cat that eats the most or least
smallest=largest=food[0]; //initialize the smallest and largest at the first array food value
smallestName=largestName=kittyNames[0]; //initialize for the smallest and largest eaten for the first cat name in array
float totalFood; //declaration
totalFood=0; //initialization
for (int i=0;i<sizeOfArray; i++) //loop to go through cats and display their name and amount of food they ate
{
cout << kittyNames[i] << " eats "<< food[i]<< " pounds of food weekly \n";
if (smallest > food[i])
{
smallest = food[i]; //if the food amount is less than the original value then replace it
smallestName=kittyNames[i]; //change the name of the cat to the new cats name
}
if (largest < food[i])
{
smallest = food[i]; //if the food amount is more than the original then replace it
largestName = kittyNames[i]; //change the name of the cat to thew new cats name
}
totalFood+=food[i]; //keep adding the amounts of food to the total each time the loop goes through
}
cout << endl<<smallestName << " ate the least amount of food at " << smallest << " pounds \n"; //display the lowest cats name + ammount
cout << largestName << " ate the most amount of food at " << largest << " pounds \n"; //display the largest cats name + ammount
cout << "The total amount of food eaten weekly is "<<totalFood<<endl; //display total food eaten
}
The problem is that food inside the kittyfood function is a local variable and not the same as the array you have created in your main function.
The local variable gets destroyed after the function has returned and the one on main is still uninitialized thus containing garbage values.
The food array in main is not the same as the food array in kittyfood. In kittyfood you're populating a local to the function array with some values. As a result the array in main has undefined contents.
You could pass the food array to kittyfood as well, like so:
int main()
{
string names[5]={"Fluffy","Sneaky","Moonie","Stuffy","Oriana"};
float food[5];
kittyfood(names, food, 5);
}
void kittyfood(string kittyNames[], float food[], int sizeOfArray)
{
// populate the food array
}
Or you could use std::vector or std::array to make your life easier, but that is beside the question.
You read amount of food (float food[5]; variable) from standard input in kittyfood function and never use it. I guess this will help you.
void kittyfood(string kittyNames[], int sizeOfArray, float food[])
{
for (int i=0;i<sizeOfArray; i++) //loop to go through cat names and get the amounts of food they eat
{
cout << "Please enter the amount of food in pounds "<< kittyNames[i] << " eats weekly\n"; //prompt user food eaten
cin >> food[i]; //user input food eaten
while (food[i]<0)
{
cout << "This cannot be a negative ammount \n"; //input validation
cin >> food[i];
}
}
}

Sorting a two dimensional struct array [closed]

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 10 years ago.
I am attempting to sort a two dimensional struct array(ie. a struct array where each struct contains a struct array). My code sorts the parent struct and the struct inside the parent correctly. However, when the parent struct is swapped into its correct position the struct array inside it is reset to its original order.
NOTE: The student name must contain a first and last name(or the program will crash). Also the grade must be a capital "A", "B", "C", "D" or "F". I have to use a sorting algorithm that I write (i chose bubble sort). I can't use vectors or sort() functions etc.(This is homework)
Current Output:
Enter student name: Bob Chatter
Enter class title: Chem
Enter units for Chem: 3
Enter grade for Chem: A
Enter class title: Bio
Enter units for Bio: 3
Enter grade for Bio: B
Enter class title: Algebra
Enter units for Algebra: 4
Enter grade for Algebra: A
Enter class title:
Enter student name: Frank Brandon
Enter class title: Music
Enter units for Music: 3
Enter grade for Music: A
Enter class title:
Enter student name: Brad Anderson
Enter class title: CoSci
Enter units for CoSci: 3
Enter grade for CoSci: A
Enter class title:
Enter student name:
Student's name: Bob Chatter
Chem,A
Bio,B
Algebra,A
GPA: 3.70
Student's name: Frank Brandon
Music,A
GPA: 4.00
Student's name: Brad Anderson
CoSci,A
GPA: 4.00
Student's name: Brad Anderson
CoSci,A
GPA: 4.00
Student's name: Frank Brandon
Music,A
GPA: 4.00
Student's name: Bob Chatter
Chem,A
Bio,B
Algebra,A
GPA: 3.70
Press any key to continue . . .
Bob Chatters classes are not sorted, when I debug they are sorted correctly until the students are sorted by last name, at which point the sorting of the Classes reset.
#include <iostream>
#include <string>
#include <stdio.h>
#include <string.h>
#include <iomanip>
using namespace std;
struct Class
{
string title;
int units;
char grade;
};
struct Student
{
string name;
double gpa;
Class classes[500];
};
int const SIZE = 50;
void initStudent(Student[], int);
void readStudent(Student[], int, int&);
void gpaCalculate(Student&);
void print(Student[], int);
void stringToCharArray (string, char[]);
string returnLastName(string);
void sort_name(Student[], int);
void bubbleUpLastName(Student[],int, int);
void bubbleUpClass(Student[],int, int);
void swapStu(Student&, Student&);
void swapStusClass(Class&, Class&);
int main()
{
int numberOfStudents = 0;
Student students[SIZE];
initStudent(students, SIZE);
readStudent(students, SIZE, numberOfStudents);
for(int i = 0; students[i].name != "";i++)
gpaCalculate(students[i]);
print(students, numberOfStudents);
sort_name(students, numberOfStudents);
print(students, numberOfStudents);
system("pause");
return 0;
}
void initStudent(Student st[], int s)
{
for(int i = 0; i < s; i++)
{
st[i].gpa = 0.0;
}
}
void readStudent(Student st[], int s, int& nStus)
{
for(int i = 0; i < s; i++)
{
string tmpName;
cout << "Enter student name: ";
getline(cin, tmpName);
if(tmpName == "")
break;
st[i].name = tmpName;
nStus++;
for(int j = 0; j < 500; j++)
{
string tmpTitle;
cout << "Enter class title: ";
getline(cin, tmpTitle);
if (tmpTitle == "")
break;
st[i].classes[j].title = tmpTitle;
cout << "Enter units for " << st[i].classes[j].title << ": " ;
cin >> st[i].classes[j].units;
cout << "Enter grade for " << st[i].classes[j].title << ": " ;
cin >> st[i].classes[j].grade;
cin.ignore();
}
}
}
void gpaCalculate (Student& s)
{
double unitsByPoints = 0;
double totalUnits = 0;
for (int i = 0; s.classes[i].title != ""; i++)
{
int grade = 0;
char ltrGrade = s.classes[i].grade;
switch (ltrGrade)
{
case 'A':
grade = 4;
break;
case 'B':
grade = 3;
break;
case 'C':
grade = 2;
break;
case 'D':
grade = 1;
break;
case 'F':
grade = 0;
break;
}
unitsByPoints += s.classes[i].units*grade;
totalUnits += s.classes[i].units;
}
s.gpa = unitsByPoints/totalUnits;
}
void print(Student st[], int size)
{
for (int i = 0; i < size; i++)
{
cout << "Student's name: " << st[i].name << endl;
for (int j = 0; st[i].classes[j].title != ""; j++)
{
cout << st[i].classes[j].title << "," << st[i].classes[j].grade << endl;
}
cout << fixed << setprecision(2) << "GPA: " << st[i].gpa << endl;
}
}
// Returns the last name of the student passed in
string returnLastName(string s)
{
int i = 0;
while (s[i] != ' ')
{
i++;
}
return s.substr(i + 1, s.length() - (i + 1));
}
//sorts the students according to name and their classes according to their title
void sort_name(Student st[], int numValues)
{
int stuCurrent = 0;
int numClasses = 0;
while (stuCurrent < numValues - 1)
{
int classCurrent = 0;
for(int i = 0; st[stuCurrent].classes[i].title != ""; i++)
{
numClasses = i;
}
while (classCurrent < numClasses)
{
bubbleUpClass(st,classCurrent,stuCurrent);
classCurrent++;
}
bubbleUpLastName(st, stuCurrent, numValues-1);
stuCurrent++;
}
}
// Moves the student with the last name that should be first alphabeticaly into the first position of the Student array
void bubbleUpLastName(Student st[],int startIndex, int numValues)
{
for (int index = numValues; index > startIndex; index--)
{
if ((returnLastName(st[index-1].name).compare(returnLastName(st[index].name)) > 0))
{
swapStu(st[index], st[index-1]);
}
}
}
// Moves the Class that should be first alphabeticaly (according to title) into the first position of the Class array
void bubbleUpClass (Student st[],int startIndex, int stuIndex)
{
int numValues = 0;
for(int i = 0; st[stuIndex].classes[i].title != ""; i++)
numValues = i;
for(int index = numValues; index > startIndex; index--)
{
if(st[stuIndex].classes[index - 1].title.compare(st[stuIndex].classes[index].title))
{
swapStusClass(st[stuIndex].classes[index], (st[stuIndex].classes[index - 1]));
}
}
}
void swapStu(Student& s1, Student& s2)
{
Student tmp;
tmp = s1;
s1 = s2;
s2 = tmp;
}
void swapStusClass(Class& c1, Class& c2)
{
Class tmp;
tmp = c1;
c1 = c2;
c2 = tmp;
}
/*
Define a structure called Class (with uppercase C) with the following data:
title, units and grade.
Define a structure called Student with the following data:
name (full name), gpa, and classes which is an array of Class structures (all the classes the student has taken so far).
Write an initialize function that receives an array of Student structures and its size and sets the gpa of all to 0.0.
In main, create 50 Students and call the above function to initialize the gpa for all 50 Students to 0.0.
Then, pass the array of student structures and its size to a read function that will read student data from the user and store the entered data in the array of student structures. The user will enter student name followed by the class title, units and grade received for each class he or she has taken. When finished entering class information for a student, the user will just press Enter (an empty string) and to end entering more students, he or she will do the same for the student name.
Example:
Enter student name: Maria Gomez
Enter class title: English 101
Enter units for English 101: 3
Enter grade for English 101: A
Enter class title: Math 201
Enter units for Math 201: 4
Enter grade for Math 201: B
Enter class title: [User enters RETURN to indicate no more classes]
Enter student name: Kevin Duran
Enter class title: Poly Sci 101
Enter units for Poly Sci 101: 3
Enter grade for Poly Sci 101: A
Enter class title: Math 201
Enter units for Math 201: 4
Enter grade for Math 201: B
Enter class title: [User enters RETURN to indicate no more classes]
Enter student name: [User enters RETURN to indicate no more students]
Once all Studnets have been entered, pass each element of the array of Student structures (element by element) to a gpa function which will compute and return the gpa for each Student using the classes array within each Student structure which contains the units and grade for each class taken by the student. Store the gpa returned by the above function in the gpa member of the Student structures. GPA is calculated by multiplying the number of units for each class by the points received for that class, and then adding all these products together and dividing it by total number of units. The points received for a class is based on the grade: for A, it's 4; for B, it's 3; for C, it's 2; for D it's 1; and for F it's 0. For example, if a student has take 3 classes with 3, 4, and 3 units and has received A, B, and C for these classes, respectively, then, the GPA will be 3 x 4 + 4 x 3 + 3 x 2 / 10 = 3.0.
Print all students showing name, followed by all classes taken, the grade received and the gpa using a display function which receives the array and its size as parameters.
Then, using a sort_name function, sort the student structures based on their last names and for each student, sort the classes he or she is taking based on class title. Display the sorted list of students using the display function by calling it from main.
For example:
Kevn Duran
Poly Sci 101, A
Math 150, B
GPA: 3.0
Maria Gomez:
English 101, A
Math 201, C
GPA: 2.9
Robert Small
Comp Science 801, C
Comp Science 802, D
GPA: 1.9
Tom Wang
Comp Science 808, A
Comp Science 839, B
GPA: 3.5
Then, sort the students based on their GPA's using a sort_gpa function and print the list again using the display function.
Then, ask what to search for - name or gpa. If name is selected, read a student name from the user and, using a binary search function that takes the array, its size and the name to search for, finds the student and displays all of his or her information (name, gpa, units and list of classes taken).
Example:
Enter a student name: Robert Small
Robert Small:
Comp Science 801, C
Comp Science 802, B
GPA: 2.5
If GPA is selected, read a GPA and using another binary search find the student with the given GPA by passing the students array, its size and the GPA to search for. Display the name of the student with the specified GPA in main.
Example:
Enter GPA to search for: 2.5
Robert Small was found with the GPA of 2.5
If the name or GPA is not found, tell the user it was not found; e.g.: There was no student with a GPA of 2.5; or Robert Small was not found.
Then, pass the array of student atructures and the size to a stats function which will return the average of the GPA's of all students and through two reference parameters will output the student structures that have the minimum and maximum GPA's. Print the average GPA, as well as the names of the students who have the minimum and maximum GPA in main, like so:
Average GPA = 3.17
Robert Small has the minimum GPA of 2.5.
Tom Wang has the maximum GPA of 3.5.
Finally, read a maximum and minimum GPA from the user and pass the array of student structures and its size, as well as two other arrays of student structures of the same size to a function which will store all students with a GPA of above the minimum in the highGPA array and all those with a GPA below the maximum in the lowGPA array. Display the students stored in these two arrays by passing them each from main to the display function. In other words, the highlow function receives two uninitalized arrays of student structures and populates them based on the GPA criteria passed to it (minimum GPA and maximum GPA). Then, upon return to main, main passes each of these arrays to the display function to display them. For example, if the user enters 2.0 for the maximum GPA, the lowGPA array gets filled out with all those students who have a GPA of less than 2.0. Likewise, if the minimum GPA is 3.5, the highlow function populates the highGPA array with those students who have a GPA of 3.5 or higher.
Example:
Enter maximum GPA: 2.0
Enter minimum GPA: 3.5
Students with a GPA of lower than 2.0:
Robert Small 1.9
Students with a GPA of 3.5 or higher:
Tom Wang 3.5
When writing the highlow function, take advantage of the fact that the array elements are sorted based on the GPA, so to find all the students with a GPA of equal to or higher than the minimum GPA, it doesn't make sense to start from the first element in the array. Instead you can start from the midpoint. If the midpoint is lower than the minimum GPA, you can increment the index until the midpoint is no longer smaller and then all the GPA's from that point on will be larger and part of the high GPA's. For low GPA's of course, you'd want to start from the beginning of the array and compare and store each that's lower than the maximum until they are no longer lower.
Functions you must write for this assignment (in addition to main):
initialize, read, display, sort_name, sort_gpa, search-name, search_gpa, stats, highlow.
Upload your cpp and exe files using the Browse and Upload buttons below and click Finish once both have been uploaded to the site.*/
What is causing the struct array inside the parent struct to be reset?
When comparing Class::title you forgot to add comparison to compare value:
Your line:
if(st[stuIndex].classes[index - 1].title.compare(st[stuIndex].classes[index].title))
Should be:
if(0 < st[stuIndex].classes[index - 1].title.compare(st[stuIndex].classes[index].title))
I say you forgot - because you have this explicit comparison in your function to sort students.
Now explanation of your result: at first, just by chance - the classes for some student are sorted, but after that position of your student changes (this is bubble sort) and next sorting is done on these classes - so because actually you don't sort classes, but just changes its positions, you can have their original sequence in next step.
As a bonus I advice not to use compare for sorting - just use operator <:
if(st[stuIndex].classes[index - 1].title < st[stuIndex].classes[index].title)
much simpler, isn't it?

Sorting Array's of Structs

I am working on an assignment for my C++ class (the assignment is pasted at the bottom of my test.cpp file). I implemented everything correctly up until the last requirement (using a sort_name function, sort the student structures based on their last names and for each student, sort the classes he or she is taking based on class title. Display the sorted list of students using the display function by calling it from main). I have attempted to implement my sort function by sorting just the students at first, but I keep getting errors and getting stuck(The current error is: Unhandled exception at 0x777a15de in 839a4 Vasilkovskiy.exe: 0xC00000FD: Stack overflow). Any help would be greatly appreciated.
NOTE: I understand that vectors are much more useful for sorting, but our professor does not want us to use them.
#include <iostream>
#include <string>
#include <stdio.h>
#include <string.h>
#include <iomanip>
using namespace std;
struct Class
{
string title;
int units;
char grade;
};
struct Student
{
string name;
double gpa;
Class classes[500];
};
int const SIZE = 50;
void initStudent(Student[], int);
void readStudent(Student[], int, int&);
void gpaCalculate(Student&);
void print(Student[], int);
void sort_name(Student[], int);
void swapStus(Student&, Student&);
void stringToCharArray(string, char[]);
int locactionOfFirstName(Student[], int, int);
int main()
{
int numberOfStudents = 0;
Student students[SIZE];
initStudent(students, SIZE);
readStudent(students, SIZE, numberOfStudents);
for(int i = 0; students[i].name != "";i++)
gpaCalculate(students[i]);
print(students, numberOfStudents);
sort_name(students, numberOfStudents);
system("pause");
return 0;
}
void initStudent(Student st[], int s)
{
for(int i = 0; i < s; i++)
{
st[i].gpa = 0.0;
}
}
void readStudent(Student st[], int s, int& nStus)
{
for(int i = 0; i < s; i++)
{
string tmpName;
cout << "Enter student name: ";
getline(cin, tmpName);
if(tmpName == "")
break;
st[i].name = tmpName;
nStus++;
for(int j = 0; j < 500; j++)
{
string tmpTitle;
cout << "Enter class title: ";
getline(cin, tmpTitle);
if (tmpTitle == "")
break;
st[i].classes[j].title = tmpTitle;
cout << "Enter units for " << st[i].classes[j].title << ": " ;
cin >> st[i].classes[j].units;
cout << "Enter grade for " << st[i].classes[j].title << ": " ;
cin >> st[i].classes[j].grade;
cin.ignore();
}
}
}
void gpaCalculate (Student& s)
{
double unitsByPoints = 0;
double totalUnits = 0;
for (int i = 0; s.classes[i].title != ""; i++)
{
int grade = 0;
char ltrGrade = s.classes[i].grade;
switch (ltrGrade)
{
case 'A':
grade = 4;
break;
case 'B':
grade = 3;
break;
case 'C':
grade = 2;
break;
case 'D':
grade = 1;
break;
case 'F':
grade = 0;
break;
}
unitsByPoints += s.classes[i].units*grade;
totalUnits += s.classes[i].units;
}
s.gpa = unitsByPoints/totalUnits;
}
void print(Student st[], int size)
{
for (int i = 0; i < size; i++)
{
cout << "Student's name: " << st[i].name << endl;
for (int j = 0; st[i].classes[j].title != ""; j++)
{
cout << st[i].classes[j].title << "," << st[i].classes[j].grade << endl;
}
cout << fixed << setprecision(2) << "GPA: " << st[i].gpa << endl;
}
}
//void sort_name(Student st[], int size)
//{
// for(int i = 0; i < size; i++)
// {
// int smallest = locactionOfFirstName(st, i, size);
// swapStus(st[i], st[smallest]);
// }
//
//}
void swapStus(Student& s1, Student& s2)
{
Student tempStu;
tempStu = s1;
s1 = s2;
s2 = tempStu;
}
void stringToCharArray(string s, char c[])
{
char tempCharArray[50];
for(int i = 0; s[i] != '\n'; i++)
{
tempCharArray[i] = s[i];
}
char * space = strstr(tempCharArray," ");
strcpy(c,space);
}
bool lastNameCompare(string l1, string l2)
{
char lName1[50];
char lName2[50];
stringToCharArray(l1, lName1);
stringToCharArray(l2, lName2);
return (strcmp(lName1, lName2) >=0);
}
int locactionOfFirstName(Student st[],int start, int size)
{
char lName1[50];
char lName2[50];
stringToCharArray(st[0].name, lName1);
int i;
for(i = start; i < size;)
{
stringToCharArray(st[i].name, lName2);
if(strcmp(lName1, lName2) >= 0 )
{
stringToCharArray(st[i].name, lName1);
}
}
return i;
}
void InsertItem(Student values[], int startIndex, int endIndex)
{
bool finished = false;
int current = endIndex;
bool moreToSearch = (current != startIndex);
while (moreToSearch && !finished)
{
if (lastNameCompare(values[current-1].name, values[current].name))
{
swapStus(values[current], values[current-1]);
current--;
moreToSearch = (current != startIndex);
}
else
finished = true;
}
}
void sort_name(Student values[], int numValues)
{
for (int count = 0; count < numValues; count++)
InsertItem(values, 0, count);
}
/*
Define a structure called Class (with uppercase C) with the following data:
title, units and grade.
Define a structure called Student with the following data:
name (full name), gpa, and classes which is an array of Class structures (all the classes the student has taken so far).
Write an initialize function that receives an array of Student structures and its size and sets the gpa of all to 0.0.
In main, create 50 Students and call the above function to initialize the gpa for all 50 Students to 0.0.
Then, pass the array of student structures and its size to a read function that will read student data from the user and store the entered data in the array of student structures. The user will enter student name followed by the class title, units and grade received for each class he or she has taken. When finished entering class information for a student, the user will just press Enter (an empty string) and to end entering more students, he or she will do the same for the student name.
Example:
Enter student name: Maria Gomez
Enter class title: English 101
Enter units for English 101: 3
Enter grade for English 101: A
Enter class title: Math 201
Enter units for Math 201: 4
Enter grade for Math 201: B
Enter class title: [User enters RETURN to indicate no more classes]
Enter student name: Kevin Duran
Enter class title: Poly Sci 101
Enter units for Poly Sci 101: 3
Enter grade for Poly Sci 101: A
Enter class title: Math 201
Enter units for Math 201: 4
Enter grade for Math 201: B
Enter class title: [User enters RETURN to indicate no more classes]
Enter student name: [User enters RETURN to indicate no more students]
Once all Studnets have been entered, pass each element of the array of Student structures (element by element) to a gpa function which will compute and return the gpa for each Student using the classes array within each Student structure which contains the units and grade for each class taken by the student. Store the gpa returned by the above function in the gpa member of the Student structures. GPA is calculated by multiplying the number of units for each class by the points received for that class, and then adding all these products together and dividing it by total number of units. The points received for a class is based on the grade: for A, it's 4; for B, it's 3; for C, it's 2; for D it's 1; and for F it's 0. For example, if a student has take 3 classes with 3, 4, and 3 units and has received A, B, and C for these classes, respectively, then, the GPA will be 3 x 4 + 4 x 3 + 3 x 2 / 10 = 3.0.
Print all students showing name, followed by all classes taken, the grade received and the gpa using a display function which receives the array and its size as parameters.
Then, using a sort_name function, sort the student structures based on their last names and for each student, sort the classes he or she is taking based on class title. Display the sorted list of students using the display function by calling it from main.
For example:
Kevn Duran
Poly Sci 101, A
Math 150, B
GPA: 3.0
Maria Gomez:
English 101, A
Math 201, C
GPA: 2.9
Robert Small
Comp Science 801, C
Comp Science 802, D
GPA: 1.9
Tom Wang
Comp Science 808, A
Comp Science 839, B
GPA: 3.5
Then, sort the students based on their GPA's using a sort_gpa function and print the list again using the display function.
Then, ask what to search for - name or gpa. If name is selected, read a student name from the user and, using a binary search function that takes the array, its size and the name to search for, finds the student and displays all of his or her information (name, gpa, units and list of classes taken).
Example:
Enter a student name: Robert Small
Robert Small:
Comp Science 801, C
Comp Science 802, B
GPA: 2.5
If GPA is selected, read a GPA and using another binary search find the student with the given GPA by passing the students array, its size and the GPA to search for. Display the name of the student with the specified GPA in main.
Example:
Enter GPA to search for: 2.5
Robert Small was found with the GPA of 2.5
If the name or GPA is not found, tell the user it was not found; e.g.: There was no student with a GPA of 2.5; or Robert Small was not found.
Then, pass the array of student atructures and the size to a stats function which will return the average of the GPA's of all students and through two reference parameters will output the student structures that have the minimum and maximum GPA's. Print the average GPA, as well as the names of the students who have the minimum and maximum GPA in main, like so:
Average GPA = 3.17
Robert Small has the minimum GPA of 2.5.
Tom Wang has the maximum GPA of 3.5.
Finally, read a maximum and minimum GPA from the user and pass the array of student structures and its size, as well as two other arrays of student structures of the same size to a function which will store all students with a GPA of above the minimum in the highGPA array and all those with a GPA below the maximum in the lowGPA array. Display the students stored in these two arrays by passing them each from main to the display function. In other words, the highlow function receives two uninitalized arrays of student structures and populates them based on the GPA criteria passed to it (minimum GPA and maximum GPA). Then, upon return to main, main passes each of these arrays to the display function to display them. For example, if the user enters 2.0 for the maximum GPA, the lowGPA array gets filled out with all those students who have a GPA of less than 2.0. Likewise, if the minimum GPA is 3.5, the highlow function populates the highGPA array with those students who have a GPA of 3.5 or higher.
Example:
Enter maximum GPA: 2.0
Enter minimum GPA: 3.5
Students with a GPA of lower than 2.0:
Robert Small 1.9
Students with a GPA of 3.5 or higher:
Tom Wang 3.5
When writing the highlow function, take advantage of the fact that the array elements are sorted based on the GPA, so to find all the students with a GPA of equal to or higher than the minimum GPA, it doesn't make sense to start from the first element in the array. Instead you can start from the midpoint. If the midpoint is lower than the minimum GPA, you can increment the index until the midpoint is no longer smaller and then all the GPA's from that point on will be larger and part of the high GPA's. For low GPA's of course, you'd want to start from the beginning of the array and compare and store each that's lower than the maximum until they are no longer lower.
Functions you must write for this assignment (in addition to main):
initialize, read, display, sort_name, sort_gpa, search-name, search_gpa, stats, highlow.
Upload your cpp and exe files using the Browse and Upload buttons below and click Finish once both have been uploaded to the site.*/
I debugged it for you.
The problem is in your stringToCharArray(string s, char c[]).
My index i arrived to 104 before getting "segmentation fault". Since all your strings have length 50 you are clearly going out of bounds.
Another problem is in srtstr that returns NULL, but this is related to the first problem.
A quick look to your sort_name and InsertItem didn't show up anything wrong, at least in the field of "segmentation error", since it's not so clear what you are trying to do, but at least you are performing the right index checks.