1
votes

I am a beginner in C++. I am trying to write a simple program that creates records of student_info. I create an array of structs with member variables name and a vector of homework grades. I wish to read from terminal input cin into this array of structs. Please find below my attempt to do this. What I am confused about is how to terminate/ exit the read loop in the program while running the program. I need to continue reading name and a bunch of homework grades that forms a single record. If I delete is.clear() then it only gets one record, when I type in the name of the next student the program exits.

I would greatly appreciate any suggestions.

#include <cstdlib>
#include <string>
#include <iostream>
#include <vector>
using namespace std;

struct student_info{
  string name;
  vector<double> hw_grades;
};

istream& read_single_record (istream& is, student_info& s){
  is>>s.name;
  double x;
  while(is>>x)
  {
     s.hw_grades.push_back(x);
  }
  is.clear();
  return is;}

int main() {
  //read data into an array of student info
  vector<student_info> vec_st_info;
  student_info x;
  while(read_single_record(cin,x))
  {
    vec_st_info.push_back(x);
  }             
  return 0;
  }

A sample input for the program will be

John
88
98
89
67
Sam
78
90
Tom
89
90
76

The name followed by a sequence of homework grades each entered with a 'return' key. The number of homework grades is also not fixed.

1
You need some actual logic to determine when a record is finished. For example, if the format is for all values in a record to be entered on a single line, you should use std::getline and then read from a string using std::istringstream. If all values are to be on separate lines, and separated by a blank line, std::getline will help again in this case. If there's a sentinel value (such as -1) for a grade that ends the record, make sure you are handling that. Otherwise, you may need to read one character at a time, and putback the character if it doesn't look like a number. - paddy
Thanks for your comment. This is a simplified version of the code in Accelerated C++, I have not changed any structural details of the code. I don't see that they are using any special check to determine when the record is finished. Is there any way I can say assign a character or an input e.g. cmd + D to say that the record is finished - vishmay
It would help if you included an example in your question showing exactly what the input looks like. - paddy
@Ghooo by deleting your answer, you ensured that the useful discussion in the comments are not visible to the OP. I was about to reply that my comments were essentially the same as your answer but leaving the return type as istream& instead of changing to bool. - paddy
Thanks for your comment. can you please post a reply showing the code that does that. I need to be able to press ctr+D to terminate the input of all the records. I have also included a sample input. Many thanks for your help - vishmay

1 Answers

0
votes

This should be fixed by returning when you fail to read name:

istream& read_single_record (istream& is, student_info& s)
{
  if( !(is>>s.name) ) return is;
  double x;
  while( is>>x )
  {
     s.hw_grades.push_back(x);
  }
  is.clear();
  return is;
}

The reason this fixes the hang is because the stream remains in an error state when you fail to read the string. Before, you always cleared the state prior to returning.