Displaying average age and youngest student's name

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


main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#include <iostream>
#include <fstream>
#include <iomanip>
#include "Student1.h"
#include "Student2.h"
#include "ageCalc.h"
using namespace std;

const int SIZE = 100;

int main()
{
	ifstream inFile;
	inFile.open("Students.txt", ios::in|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.
	Student1 **ptrArr = new Student1 *[SIZE];

	for(int i = 0; i < SIZE; i++)
	{
		ptrArr[i] = nullptr;
	}

	Student1 s;
	int total = 0;
	// read the first input record
	inFile.read(reinterpret_cast<char *> (&s), sizeof(s));

	while(!inFile.eof())
	{
		// dynamically allocate space for new student variable
		ptrArr[total] = new Student1;

		// populate the student variable from the input
		*ptrArr[total] = s;
		total++;

		// read the next input record
		inFile.read(reinterpret_cast<char *> (&s), sizeof(s));
	}

	inFile.close();

	Student2 *st = new Student2[SIZE];
	for(int i = 0; ptrArr[i]; i++)
	{
		for(char fn: ptrArr[i]->first_name)
			st[i].fn += fn;

		st[i].mi = ptrArr[i]->middle_int[0];

		for(char ln: ptrArr[i]->last_name)
			st[i].ln += ln;

		st[i].cc = ptrArr[i]->campus_code;

		for(char sID: ptrArr[i]->student_ID)
			st[i].sID += sID;

		st[i].age = atoi(ptrArr[i]->age);
	}

	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; st[j].age != 0; j++)
	{
		cout << st[j].fn << setw(8);
		cout << st[j].mi << "       ";
		cout << st[j].ln << setw(2);
		cout << st[j].cc << "          ";
		cout << st[j].sID << setw(16);
		cout << st[j].age << " " << endl;
 	}

	Student2 *y;
	int avg = ageCalc(&st, y);

	cout << "Average student age is: " << avg << " years." << endl;
	cout << "Youngest student is: " << y->fn << " " << y->mi << " " << y->ln << endl;

	for(int x = 0; ptrArr[x]; x++)
	{
		delete [] ptrArr;
		delete [] st;
	}

	return 0;
}


ageCalc.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include "Student2.h"
using namespace std;

int ageCalc(Student2 *arr[], Student2 *&y)
{
	int i = 0, sum = 0, index = 0, avg;
	int youngest = 150;

	while(arr[i] != nullptr)
	{
		sum += arr[i]->age;
		i++;

		if(arr[i]->age < youngest)
		{
			youngest = arr[i]->age;
			index = i;
		}
	}

	y = arr[index];
	avg = sum / i;

	return avg;
}


Student1.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#ifndef STUDENT1_H_
#define STUDENT1_H_
#include <iostream>
using namespace std;

struct Student1
{
	char first_name[10];
	char middle_int[10];
	char last_name[20];
	char campus_code;
	char student_ID[8];
	char age[3];
};

#endif 


Student2.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#ifndef STUDENT2_H_
#define STUDENT2_H_
#include <iostream>
#include <string>
using namespace std;

struct Student2
{
	string fn;
	char mi;
	string ln;
	char cc;
	string sID;
	short int age;
};

#endif 


ageCalc.h
1
2
3
4
5
6
#ifndef AGECALC_H_
#define AGECALC_H_
#include "Student2.h"

int ageCalc(Student2 *[], Student2 *&);
#endif 


Current Output
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
Last edited on
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.
Last edited on
Consider:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#include <iostream>
#include <fstream>
#include <iomanip>
#include <cctype>
using namespace std;

const int 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;
	short int 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;
	const int 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:


Youngest student is: Richard    E Pollidence


which is not as required.
Last edited on
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.
Topic archived. No new replies allowed.