C++ Reading Records from Disc File, Sorting, and Finding the Average

Hi everyone.

I hope all is well.

I am having trouble with my code below.

For my C++ class, my professor has just uploaded an assignment that requires us to read all records from a disc file to:

1. Arrays.
2. Structure of records: student number (2 bytes), student name (20 bytes), and grade (integer).
3. Sort the list according to test scores.
4. Display the average test score of the class.
5. Save sorted records to a new disc file.

The disc file mentioned above:

1 Sanna Saunders     89
2 Kelly Handley      95
3 Arif Crane         76


I feel like I have only part 1 complete, which was to rewrite the original disc files using a strut function, but I'm not sure how I can use an array to sort out these elements. Do I just input those numbers/scores: "89, 95,76" as elements (in square brackets []) or is there another way to do it?

I also need the code to be an average between all three numbers listed above. So there should be a formula that holds the averaged value, divided by the three scores: 89 + 95 + 76 = 260, 260/3 = 86.3
or
sum += scores
average = sum / scores


Lastly, the code should also be sorted in ascending order, so it should look like:

3 Arif Crane       76     
1 Sanna Saunders     89
2 Kelly Handley      95


I'm not sure what else I can add. I know there's still so much left to do to meet the criteria for this assignment, and I've also written a similar code for a similar assignment which also had to do with arrays and sorting, but those numbers came from user input. Now these numbers are given: 89, 95, and 76, so I'm not sure how I can modify that accordingly.

Please, if anyone can or has the time, take a look at my code and run it. Thanks in advance.

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
#include <iostream>
#include <string>
using namespace std;

struct students{
  string studentName;
  float testScore;
};

int main(){

  struct students active[3] = {
  {"Student 1: Sanna Saunders:\t", 89},
  {"Student 2: Kelly Handley:\t", 95},
  {"Student 3: Arif Crane: \t", 76}};

struct students *record = active;

cout << "\nThe records in the original file are: \n\n";
while (record <= &active[2]){
  cout << " " << record -> studentName << " " << record -> testScore << " " << endl;
  record ++;
}

cout << "\n The records in the new file are now sorted: \n\n";
return 0;
}
Last edited on
I may or may not have to delete the struct function, as I now realize I could replace that with an array, but I'll keep trying it out.
Last edited on
Why array and not a vector? Why are the bytes given for the structure?

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
#include <iostream>
#include <fstream>
#include <string>
#include <algorithm>
#include <iomanip>

struct Student1 {
	short sno {};
	std::string name {};
	int grade {};
};

std::istream& operator>>(std::istream& is, Student1& student)
{
	std::string name;

	is >> student.sno >> student.name >> name >> student.grade;
	student.name += ' ' + name;

	return is;
}

std::ostream& operator<<(std::ostream& os, const Student1& student)
{
	return os << student.sno << '\t' << student.name << '\t' << student.grade;
}

void output(std::ostream& os, const Student1 students[], size_t no)
{
	for (size_t i = 0; i < no; ++i)
		os << students[i] << '\n';
}

int main()
{
	std::ifstream ifs("students.txt");

	if (!ifs.is_open())
		return (std::cout << "Cannot open file\n"), 1;

	const size_t maxSize {10};
	Student1 students[maxSize] {};
	size_t cnt {};
	int total {};

	for (Student1 s; ifs >> s; students[cnt++] = s, total += s.grade);
	output(std::cout, students, cnt);
	std::sort(std::begin(students), std::begin(students) + cnt, [](const auto& s1, const auto& s2) { return s1.grade < s2.grade; });

	std::cout << '\n';
	output(std::cout, students, cnt);
	std::cout << std::fixed << std::setprecision(2) << "\nAverage grade is " << (total + 0.0) / cnt << '\n';

	std::ofstream ofs("students1.txt");
	output(ofs, students, cnt);
}

Hello allisonOs,

First suggestion is DO NOT try to do everything at once. Work on your program in small parts. Write it, compile it and test it as often as needed.

To start with:

that requires us to read all records from a disc file to:


So the first code to work with is reading the file for 1 record and store the information. the line: struct students active[3]{}; is good to start with.

Once you can read the file and store the information then Then you can adjust the program to read the whole file before moving on to the next step. Till then you have nothing to work with.

I would take lines 12 - 15 and put a comment on them for future use and use the definition of "active" as I showed you.

Andy
Hello allisonOs,

While working on the program I noticed your struct:
1
2
3
4
5
struct students
{
    string studentName;
    float testScore;
};

Does not contain a variable for "studentNumber", but your file does:

1 Sanna Saunders     89
2 Kelly Handley      95
3 Arif Crane         76



Andy
Hello allisonOs,

When I was reading this:
2. Structure of records: student number (2 bytes), student name (20 bytes), and grade (integer).

Does this mean that you need a character array of 20 or can you use a "std::string"?

If you use the string you may have to limit its input to 20 or cut it down to 20.

Andy

Bytes usually mean character arrays/C-strings, especially when the file appears to be a fixed width type
(1 character for the "id", 19 characters for the name).

Hi everyone,

Apologies for replying late.

I was actually working on the code for a while and researching alternative ways to sort out the struct I started with. I may or may not keep it depending on how this turns out. After I manage to sort whichever code works, I will keep it and find the average score from there (which I might also need to research a little because I'm not sure how it would work using arrays).

I came back with a new format that doesn't seem to work or process on my end. I'm not sure why but it has something to do with the brackets for my void function ( { } ) after the int main () function.

Anyway, assuming it works, it's supposed to look like:

The records in the original file are:
Student 1 Sanna Saunders 89 Student 2 Kelly Handley 95 Student 3 Arif Crane 76

The sorted values are: 
Student 3 Arif Crane 76 Student 1 Sanna Saunders 89 Student 3 Kelly Handley 95


It is a work in progress, and the output is messy (not listed like an array), but I can fix it later using \n or other string literals. I just need the code to actually run.

Are the header files the issue? Is there something I have to remove? I'm not sure why it's not running. Any suggestions?

I pasted a another version of the code below if you are able to look at it. Thanks again.

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
#include <iostream>
#include <string>
using namespace std;

struct students{
  string studentName; //allows student name/characters.
  float testScore; //a number.
};

void sortArray (students array[], int size);
void showArray (const students array [], int size);

int main(){

const int SIZE = 3;

students values[SIZE];

values[0].studentName = "Student 1 Sanna Saunders";
values[0].testScore = 89;

values[1].studentName = "Student 2 Kelly Handley";
values[1].testScore = 95;

values[2].studentName = "Student 3 Arif Crane";
values[2].testScore = 76;

//display values and names
cout << "The records in the original file are:\n";
showArray (values, SIZE);

//Sort values and names in ascending order.
sortArray(values, SIZE);

cout << "\nThe sorted values are:\n";
showArray (values, SIZE);

system ("pause");
return 0;
}

void sortArray(students array [], int size) {
  bool swapped;
  
  do {
    swapped = false;
    for (int count = 0; count < (size - 1); count++){
      if (array [count].testScore > array[count + 1].testScore){
        swap (array [count], array [count + 1]);
        swapped = true;
      }
    }
  while (swapped); //loop again if swapped occurred
  }
}

void showArray(const students array[], int size) {
  for (int count = 0; count < size; count++)
  cout << array [count].testScore << " " << array[count].studentName < " ";
  count << endl;
}

Last edited on
Using the test data given originally, with a custom sort comparator:
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
#include <iostream>
#include <fstream>
#include <cstring>   // strtok, strncpy, strcat
#include <cstdio>    // atoi
#include <algorithm> // std::sort

struct student
{
   int  ID;
   char name[20];
   int  test_score;
};

// function to compare the test scores of two students
// used by std::sort
bool cls_sorter(student a, student b);

int main()
{
   std::ifstream fin("text.txt");

   if (!fin) // couldn't open the file, let's get outta here!
   {
      return 1; // report error to the OS
   }

   student cls[10];

   int count { };

   char text_line[25];

   while (fin.getline(text_line, 25))
   {
      // parse out the ID as a sub-string token
      char* pch = strtok(text_line, " ");

      // convert the sub-string token to int
      cls[count].ID = atoi(pch);

      // get the first name as a sub-string token
      pch = strtok(NULL, " ");

      strncpy(cls[count].name, pch, 20);

      // get the last name as a sub-string token
      pch = strtok(NULL, " ");

      // concatenate a space to the first name
      strcat(cls[count].name, " ");

      // concatenate the last name to the first name
      strcat(cls[count].name, pch);

      // get the test score as a sub-string token
      pch = strtok(NULL, " ");

      // convert the token to an int
      cls[count].test_score = atoi(pch);

      // increment the number of items read
      count++;
   }

   std::cout << count << " student records read.\n";

   double sum { };

   for (int itr { }; itr < count; itr++)
   {
      sum += cls[itr].test_score;
   }

   double average { sum / count };

   std::cout << "The average score: " << average << '\n';

   std::sort(cls, cls + count, cls_sorter);

   std::cout << "\nThe sorted array:\n";

   for (int itr { }; itr < count; itr++)
   {
      std::cout << cls[itr].ID << '\t'
         << cls[itr].name << '\t'
         << cls[itr].test_score << '\n';
   }
}

bool cls_sorter(student a, student b)
{
   if (a.test_score < b.test_score)
   {
      return true;
   }
   return false;
}

3 student records read.
The average score: 86.6667

The sorted array:
3       Arif Crane      76
1       Sanna Saunders  89
2       Kelly Handley   95

If you are using Visual Studio you should put #define _CRT_SECURE_NO_WARNINGS before the includes to stop VS complaining the C string functions are unsafe.
@allisonOs See my previous post!
Last edited on
Topic archived. No new replies allowed.