This question is a follow-up from my previous one.
Write a program that needs to read a input file and populate a set of Student objects. Then it will display the objects, and perform some basic loop and function-based processing.
I managed to output the students' records correctly. However, I'm having some trouble with getting the average age of all students including getting the youngest student's name outputted. It supposed to come from my function ageCalc().
Students.txt
John Daniel Fuller E23123456034Malic Stephen Browscent W03023142039Richard E. Pollidence E02782635021Frank William Lomo E09912376022Colin Frankson R23234556023James Theodore Jackson D02323245059Dave Gerald Mungbean F12333221042Jim Waymo Hilbert W02785634055Barb C Bowie W02833546030Jim D Carlo S22876543033
File successfully open!
First Name MI Last Name Campus Code Student ID Age
===================================================================================
John D Fuller E 23123456 34
Malic S Browscent W 03023142 39
Richard E Pollidence E 02782635 21
Frank W Lomo E 09912376 22
Colin Frankson R 23234556 23
James T Jackson D 02323245 59
Dave G Mungbean F 12333221 42
Jim W Hilbert W 02785634 55
Barb C Bowie W 02833546 30
Jim D Carlo S 22876543 33
Expected Output
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
File successfully open!
First Name MI Last Name Campus Code Student ID Age
===================================================================================
John D Fuller E 23123456 34
Malic S Browscent W 03023142 39
Richard E Pollidence E 02782635 21
Frank W Lomo E 09912376 22
Colin Frankson R 23234556 23
James T Jackson D 02323245 59
Dave G Mungbean F 12333221 42
Jim W Hilbert W 02785634 55
Barb C Bowie W 02833546 30
Jim D Carlo S 22876543 33
Average age is: 35 years
Youngest student is: Richard E Pollidence
why all the pointers? if agecalc didn't take a pointer, you could call it with st, and minor cleanup would make it all one less level deep (the extra level does not appear to provide any utility).
i++;
if(arr[i]->age < youngest) //bug? what is i now? you incremented before using here?
y is set oddly. y is a pointer, but its set to a value.
y = arr[index]; ?!
little thing, not a issue but to learn,
you can return a calculation or whatever.
return sum/i is fine, you don't need to store this into avg and then return it, the extra variable has no purpose.
#include <iostream>
#include <fstream>
#include <iomanip>
#include <cctype>
usingnamespace std;
constint SIZEST = 100;
struct Student1
{
char first_name[10];
char middle_int[10];
char last_name[20];
char campus_code;
char student_ID[8];
char age[3];
};
struct Student2
{
string fn;
char mi;
string ln;
char cc;
string sID;
shortint age;
};
int ageCalc(Student2* arr[], Student2*& y)
{
int i = 0, index = 0;
int sum = 0;
int youngest = 150;
while (i < SIZEST && arr[i] != nullptr)
{
sum += arr[i]->age;
if (arr[i]->age < youngest)
{
youngest = arr[i]->age;
index = i;
}
i++;
}
y = arr[index];
return sum / (i + (i == 0));
}
int main()
{
ifstream inFile;
inFile.open("Students.txt", ios::binary);
// Open the input file – if it fails to open, display an error message and terminate
if (!inFile.is_open())
{
cout << "Unable to open file!";
return 1;
} else {
cout << "File successfully open!\n\n";
}
// Use a pointer array to manage all the created student variables.
Student2** ptrArr = new Student2 * [SIZEST] {};
int total = 0;
for (Student1 s; total < SIZEST && inFile.read(reinterpret_cast<char*> (&s), sizeof(Student1)); ++total)
{
// dynamically allocate space for new student variable
ptrArr[total] = new Student2 {};
for (char fn : s.first_name)
if (!isspace(fn)) ptrArr[total]->fn += fn;
ptrArr[total]->mi = s.middle_int[0];
for (char ln : s.last_name)
if (!isspace(ln)) ptrArr[total]->ln += ln;
ptrArr[total]->cc = s.campus_code;
for (char sID : s.student_ID)
ptrArr[total]->sID += sID;
ptrArr[total]->age = atoi(s.age);
}
inFile.close();
cout << "First Name" << setw(9)
<< "MI" << setw(15)
<< "Last Name" << setw(17)
<< "Campus Code" << setw(16)
<< "Student ID" << setw(15)
<< "Age" << endl;
cout << "===================================================================================" << endl;
for (int j = 0; j < total; ++j)
{
cout << left << setfill(' ');
cout << setw(17) << ptrArr[j]->fn;
cout << setw(8) << ptrArr[j]->mi;
cout << setw(21) << ptrArr[j]->ln;
cout << setw(11) << ptrArr[j]->cc;
cout << setw(22) << ptrArr[j]->sID;
cout << right << setw(3) << setfill('0') << ptrArr[j]->age << '\n';
}
Student2* y;
constint avg = ageCalc(ptrArr, y);
if (y != nullptr) {
cout << "\nAverage student age is: " << avg << " years." << endl;
cout << "Youngest student is: " << y->fn << " " << y->mi << " " << y->ln << endl;
}
for (int x = 0; x < SIZEST; x++)
{
delete ptrArr[x];
}
delete[] ptrArr;
return 0;
}
which displays the required:
File successfully open!
First Name MI Last Name Campus Code Student ID Age
===================================================================================
John D Fuller E 23123456 034
Malic S Browscent W 03023142 039
Richard E Pollidence E 02782635 021
Frank W Lomo E 09912376 022
Colin Frankson R 23234556 023
James T Jackson D 02323245 059
Dave G Mungbean F 12333221 042
Jim W Hilbert W 02785634 055
Barb C Bowie W 02833546 030
Jim D Carlo S 22876543 033
Average student age is: 35 years.
Youngest student is: Richard E Pollidence
Note that when you populate student2, you're not removing the trailing spaces from student1. Hence your display seems OK, but when you come to display the name of the youngest student without not saving the trailing spaces you get:
The average age might not be an integer, so return it as a double. That means you must be careful when computing it because sum/i is an integer. Convert 1 to a double, which will force the computer to convert the other one as well and compute the floating-point quotient: (double)sum / i
Use a for() loop when possible to to express a loop. It makes the code easier to read.
You have three variables involved in tracking the youngest: index, youngest, and y. Keeping all of them in sync is an invitation to a bug. Don't use two (or three) variables when one will do:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
double ageCalc(Student2 *arr[], Student2 *&y)
{
int sum = 0;
int i;
y = arr[0];
for (i=0; arr[i]; ++i) {
sum += arr[i]->age;
if(arr[i]->age < arr[y].age) {
y = arr[i];
}
}
return (double)sum / i;
}
That assumes that there is at least one element in the array and that there is at least one nullptr element at the end. If there is a problem reading the file after opening, then all elements of arr will be nullptr and i will be 0 for the division - generating an error. If there are no nullptr elements, then the loop will attempt to access memory beyond that allocated with unknown results.
Also I think you mean:
1 2
if(arr[i]->age < y->age) {
....
The expected output above shows 35 for the average age - an int, not a double. The actual average age is 35.8
The original assignment guaranteed a nullptr at the end of the array. If the array is empty, it will return 0.0 / 0.0, which should return NaN, which is appropriate for that case.