-2

I am learning C++, and one of my lessons is having me read from a file into an an array of structs(is that how I refer to this?). I am having issues where my code compiles fine, but sits and spins on a blank screen. I am fairly sure that the issue lies with how I read the file in.

#include <fstream>
#include <iomanip>
#include <iostream>
using namespace std;

int main() {
    ifstream inputFile;
    const int SIZE = 150;
    int count = 0;
    int index[150] = {};
    inputFile.open("lab9input.dat");
    struct Student {
        string name;
        int studentID;
        int credits;
        int gpa;
    } students[SIZE];
    while (count < SIZE && inputFile >> students[count].name >>
                               students[count].studentID >>
                               students[count].credits >> students[count].gpa) {
        count++;
    }
    cout << endl << "The highest GPA student(s) is: " << endl;
    for (int i = 0; i < count; i++) {
        int high = 0, j = 0;
        if (students[i].gpa > high) {
            high = students[i].gpa;
            for (int k = 0; k < 150; k++) {
                index[k] = 0;
            }
            index[j] = i;
        }
        if (students[i].gpa == high) {
            j++;
            index[j] = i;
        }
    }
    for (int i = 0; i < 150; i++) {
        if (index[i] != 0) {
            cout << students[index[i]].name << " "
                 << students[index[i]].studentID << " "
                 << students[index[i]].credits << " " << setprecision(2)
                 << students[index[i]].gpa;
        }
    }
}

For reference, my text file looks like this:

Wesley s012980520 30 3.5
Allen s094589012 120 3.29
Jim   s980469026 145 3.85
Luke s098419346 180 3.6
Helen s124598670 60  3.85
Chole s123309870 60 3.0

Am I missing something glaringly obvious? Thank you for the help!

brc-dd
  • 2,351
  • 3
  • 10
  • 25
  • 2
    [Why is `iostream::eof()` inside a loop condition (i.e. `while (!stream.eof())`) considered wrong?](https://stackoverflow.com/questions/5605125/why-is-iostreameof-inside-a-loop-condition-i-e-while-stream-eof-cons) Try `while(count < SIZE && inputFile >> students[count].name >> students[count].studentID >> students[count].credits >> students[count].gpa) ++count;` – Ted Lyngmo Nov 16 '20 at 05:45
  • 1
    You're missing functions. You can't do much in C++ without at least a `main` function. – user4581301 Nov 16 '20 at 05:45
  • You haven't posted any part of your code that would produce any output. What have you written that would lead you to expect anything else to happen? – Nathan Pierson Nov 16 '20 at 05:45
  • 2
    I recommend giving [mre] a read and applying what it teaches to your problem. If making the MRE doesn't help you resolve the problem, post the MRE here. – user4581301 Nov 16 '20 at 05:47
  • The rest of my code is a for loop printing out students[] and a selection sort function, followed by another for loop printing out the sorted students[]. – Ryan Silveira Nov 16 '20 at 05:48
  • 1
    You want to present a complete program that misbehaves exactly the same way with s little code as possible. That way those of us out here can drop your code into our compilers and run the results to see exactly what you're seeing. Right now I can make guesses at what went wrong (see the link posted by @TedLyngmo) but I can't guarantee that your program reaches that bug or gets unlucky, bypasses the EOF bug, and fails somewhere else. – user4581301 Nov 16 '20 at 05:50
  • 1
    Do any of the student names in your input file have a space in them? – Nathan Pierson Nov 16 '20 at 05:50
  • 1
    `s012980520` Is not a valid `int` and cannot be read into `students[count].studentID`. Consider using a `std::string` instead of an `int`. – user4581301 Nov 16 '20 at 06:41
  • 1
    @user4581301 also, OP should make `gpa` a floating point number. – brc-dd Nov 16 '20 at 06:41
  • 1
    You have loops going to `150` but you only have `count` students in the array. – Ted Lyngmo Nov 16 '20 at 06:43
  • More modern way to solve the problem: https://wandbox.org/permlink/2p0Lbeax2rmjz1ch – brc-dd Nov 16 '20 at 06:54

1 Answers1

1

Here are some of the problems in your code:

  1. Data type of different variables: Your data (say Wesley s012980520 30 3.5) is of the format string string int float, which clearly does not match with the types in your struct Students.

    To fix this, simply change your struct to:

    struct Student {
        string name;
        string studentID;
        int credits;
        float gpa;
    } students[SIZE];
    

    Also, high should be float (as it stores gpa).

  2. high and j become 0 on each iteration. Move high above the loop and j to init-list of the loop, like this:

    float high = 0;
    for (int i = 0, j = 0; i < count; i++)
    
  3. index[j] = i; (first-occurrence) assigns index of student with highest gpa to index[j] but prior to this, j = 0 (although the index array is reset).

  4. The second if condition (if (students[i].gpa == high)) inside the loop assigns the index of student with highest gpa to index[1], if the conditional block above it has executed. Make it else if to prevent redundancy.

Suggestions:

  1. There is a setprecision(2), if you have put it display 3.6 as 3.60 then you need to add fixed before that.

  2. There is no need to traverse whole index array, you simply need to do that from 0 to count.

  3. Remove magic number 150 from your code, use the constant you have declared instead.

  4. Put an endline ('\n') after printing each Student object.

  5. Don't use std::endl to put simple newline characters. Use it only if you also need to flush the stream.

  6. Avoid putting using namespace std; at top of your code.

  7. Why put " when ' can do the job ;).

  8. ifstream inputFile and inputFile.open can be written in a single line like : ifstream inputFile("...").


Corrected Code (doesn't work if name has spaces in it):

#include <fstream>
#include <iomanip>
#include <iostream>
using namespace std; // <-- (10), remove this yourself

int main() {
  ifstream inputFile("lab9input.dat"); // <-- (12)
  const int SIZE = 150;
  int count = 0;
  int index[SIZE] = {}; // <-- (7)
  struct Student {
    string name;
    string studentID; // <-- (1)
    int credits;
    float gpa; // <-- (1)
  } students[SIZE];
  while (count < SIZE && inputFile >> students[count].name >>
                             students[count].studentID >>
                             students[count].credits >> students[count].gpa)
    count++;
  cout << "The highest GPA student(s) is(are): \n"; // <-- (9)
  float high; // <-- (1), (2)
  for (int i = 0, j = 0; i < count; i++) { //<-- (2)
    if (students[i].gpa > high) {
      high = students[i].gpa;
      for (int k = 0; k < 150; k++) index[k] = 0;
      j = 0; // <-- (3)
      index[j] = i;
    } else if (students[i].gpa == high) // <-- (4)
      index[++j] = i;
  }
  for (int i = 0; i < count; i++) // <--(6)
    if (index[i] != 0)
      cout << students[index[i]].name << ' ' << students[index[i]].studentID
           << ' ' << students[index[i]].credits << ' ' << fixed // <-- (5)
           << setprecision(2) << students[index[i]].gpa << '\n'; // <--(8)
}

Better code to do the same thing:

#include <algorithm>
#include <cctype>
#include <fstream>
#include <iostream>
#include <iterator>
#include <string>
#include <vector>

struct Student {
  std::string name, studentID;
  int credits;
  float gpa;

  friend std::ostream &operator<<(std::ostream &, const Student &);
  friend std::istream &operator>>(std::istream &, Student &);
};

std::ostream &operator<<(std::ostream &out, const Student &s) {
  out << s.name << ' ' << s.studentID << ' ' << s.credits << ' ' << s.gpa
      << '\n';
  return out;
}

std::istream &operator>>(std::istream &in, Student &s) {
  s.name.clear();
  std::string str;

  while (in >> str && std::none_of(str.begin(), str.end(), ::isdigit))
    s.name += str + ' ';
  s.name.pop_back();
  s.studentID = str;

  in >> s.credits >> s.gpa;
  return in;
}

int main() {
  std::ifstream is("lab9input.dat");
  std::vector<Student> v(std::istream_iterator<Student>(is), {});

  auto max_gpa = std::max_element(v.begin(), v.end(), [](auto &a, auto &b) {
                   return b.gpa > a.gpa;
                 })->gpa;

  std::cout << "The highest GPA student(s) is(are): \n";
  for (auto &i : v) if (i.gpa == max_gpa) std::cout << i;
}
brc-dd
  • 2,351
  • 3
  • 10
  • 25