File Reading Function only Reads First line then quits - c++

Problem Description
Basically, Inside of my "Roster.h" header file, i have an array of "Student" objects from the student class ( which includes the functions changeScore, SetID, setTotal,setLetterGrade). In the function that will be attached below, it is only reading the first line of data and then quitting at the while condition. I've been staring at this issue for hours now and could use a second (or third) pair of eyes. Any criticism is also appreciated, as i know that i am not the most effective programmer.It should be noted that "m_studentnum",is private data that is initialized to 0 in the constructor. Thanks in advance!
Code
void Roster::readStudentRecord(string file)
{
ifstream in;
string studentID;
string line;
int ola, cla, quiz, homework, exam, bonus, total, final = 0;
in.open(file.c_str());
getline(in, line);
while (in >> studentID) {
in >> cla >> ola >> quiz >> homework >> exam >> bonus >> total >> final;
m_students[m_studentNum].Student::setID(studentID);
m_students[m_studentNum].Student::changeScore(Student::CLA, cla);
m_students[m_studentNum].Student::changeScore(Student::OLA, ola);
m_students[m_studentNum].Student::changeScore(Student::QUIZ, quiz);
m_students[m_studentNum].Student::changeScore(Student::HOMEWORK, homework);
m_students[m_studentNum].Student::changeScore(Student::EXAM, exam);
m_students[m_studentNum].Student::changeScore(Student::BONUS, bonus);
total = cla + ola + quiz + homework + exam + bonus;
m_students[m_studentNum].Student::setTotal(total);
if (total >= 90) {
m_students[m_studentNum].Student::setLetterGrade('A');
}
else if (total >= 80 && total < 90) {
m_students[m_studentNum].Student::setLetterGrade('B');
}
else if (total >= 70 && total < 80) {
m_students[m_studentNum].Student::setLetterGrade('C');
}
else if (total >= 60 && total < 70) {
m_students[m_studentNum].Student::setLetterGrade('D');
}
else {
m_students[m_studentNum].Student::setLetterGrade('F');
}
m_studentNum++;
}
}
Data file
-note that i am doing a getline to get read in the headline for the data column's
ID CLA OLA Quiz Homework Exam Bonus Total FinalGrade
c088801 10 15 4 15 56 5
c088802 9 12 2 11 46 2
c088803 8 10 3 12 50 1
c088804 5 5 3 10 53 3
c088805 3 11 1 10 45 0
c088806 8 14 2 11 40 -1
c088807 4 12 2 12 48 -2
c088808 10 10 3 11 36 0
c088809 8 8 3 11 39 0
c088810 6 9 4 9 47 3
c088811 8 7 3 13 41 3
c088812 4 11 3 11 37 1

The "Total" and "FinalGrade" columns are empty, and you unconditionally try to read them.
When you attempt to do that, the input will contain the "ID" from the next line, and as that is not an integer, leading to the failbit flag being set for the stream which causes the loop condition to be false and the loop to end.
One possible solution is to read the while line into a string, put that string into an std::istringstream object, and read the non-empty columns as you do now. Then try to read the possibly empty columns from the input string stream.
Another solution, if those columns are supposed to be empty, is to simply not read them.

Related

How to i read from text files in which each one has a different amount of lines and setting them all as a variable to do some calculations in c++

I have 3 different text files.
P6_in1.txt
4 4 2
Max Key 10 10 10 10 20 20 20 20 100 100
Franklin Ben 10 10 10 10 20 20 20 20 100 100
Washingtonian George 10 10 0 10 20 0 0 20 100 80
P6_in2.txt
3 3 3
Key Max 15 10 15 20 30 30 60 100 80
P6_in3.txt
2 6 2
Solution Key 10 10 10 10 20 20 20 20 100 100
Washington George 10 10 10 10 20 20 20 20 100 100
Jefferson Thomas 10 0 8 6 20 15 13 0 80 90
Franklin Benjamin 0 0 0 0 20 10 20 10 100 50
Lincoln Abraham 10 5 10 5 0 0 0 0 80 30
Madisonville James 5 7 9 3 10 12 14 16 0 0
Wilson Woodrow 2 4 6 8 10 12 14 16 74 89
Hoover Herbert 0 10 10 10 0 20 20 20 0 100
Roosevelt Franklin 0 0 0 0 0 0 0 0 0 0
I need to write a program that works for all 3 which reads in all this information. It skips the first line and then assigns each name to a variable and each number to a variable so later i can use those variables to do some simple math. Ill also have to format it something like this but im just not sure how to read each name and number in and assign them to a variable.
enter image description here
A good technique is to model a class or struct to one record or text line.
struct Student
{
std::string first_name;
std::string last_name;
std::vector<unsigned int> grades;
};
Next, overload operator>> to read in the structure:
struct Student
{
std::string first_name;
std::string last_name;
std::vector<unsigned int> grades;
friend std::istream& operator>>(std::istream& input, Student& s);
};
std::istream& operator>>(std::istream& input, Student& s)
{
input >> s.first_name;
input >> s.last_name;
std::string text_line;
std::getline(input, text_line);
std::istringstream text_stream;
unsigned int grade = 0;
while (text_stream >> grade)
{
r.grades.push_back(grade);
}
return input;
}
With the above code fragment, you could read a file:
//...
unsigned int a, b, c;
//...
my_file >> a >> b >> c;
std::vector<Student> classroom;
Student s;
while (my_file >> s)
{
classroom.push_back(s);
}

How do can I get rid of the blank lines that are created c++?

Edit:
Thank you all for the quick and helpful replies. I got it working now. It was because I had to reset the counter.
I have come to ask for help as my professor is not giving me the help I need. I am new to c++ and I am trying to program a program that displays all the integers from 1 to 100 that are divisible by 6 or 7, but not both. and I have to display 5 numbers per row. I got it working except I have blank lines forming in certain areas. I don't know if it's because of how I set up the counter or what.
Here is what I got.
#include <iostream>
using namespace std;
int main()
{
int counter = 0; // Counter for creating new lines after 5 numbers
for (int numRange = 1; numRange <= 100; ++numRange) // Starts the loop of number 1 to 100
{
if (numRange % 6 == 0 || numRange % 7 == 0) // Makes the numbers divisible by 6 and 7
{
cout << numRange << " "; // Displays the output of the divisible numbers
counter++; // Starts the counter
}
if (counter % 5 == 0) // using the counter to create new lines after 5 numbers displayed
{
cout << endl; // Creates a new line
}
}
return 0;
}
This is what is outputted:
6 7 12 14 18
21 24 28 30 35
36 42 48 49 54
56 60 63 66 70
72 77 78 84 90
91 96 98
and this is what it's supposed to look like
6 7 12 14 18
21 24 28 30 35
36 48 49 54 56
60 63 66 70 72
77 78 90 91 96
98
The problem that you're seeing is due to the fact that you are checking for "5 outputs" on every loop, rather than only on ones where a number has been output! So, to fix this issue (there are others), put the counter % 5 == 0 test inside the preceding if block:
for (int numRange = 1; numRange <= 100; ++numRange) // Starts the loop of number 1 to 100
{
if (numRange % 6 == 0 || numRange % 7 == 0) // Makes the numbers divisible by 6 and 7
{
cout << numRange << " "; // Displays the output of the divisible numbers
counter++; // Increments the counter
if (counter % 5 == 0) // Only need this if we have done some output!
{
cout << endl; // Creates a new line
}
}
}
Another problem is that, in this requirement:
that are divisible by 6 or 7, but not both
your code doesn't check for the "but not both" part (but that's not the 'title' question, and I'm not going to do all your homework in one fell swoop).

Blank Screen while inputting from file c++

So i am working on my project and i am facing a problem. Every time i try to input data from file in c++ i got blank screen
The code :
int main() {
string make[1000],model[1000],partName[1000];
int partNo[1000],quantity[1000];
double price[1000];
int i = 0;
ifstream myFile("file.txt");
while (!myFile.eof())
{
myFile >> make[i] >>model[i]>> partNo[i] >>quantity[i]>> price[i]>>partName[i];
i++;
}
for (int j = 0;j < i;j++)
cout << make[j] <<"\t"<<model[j]<<"\t"<< partNo[j] <<"\t"<<quantity[j]<<"\t"<< price[j]<<"\t"<<partName[j]<<endl;
return 0;
}
a sample from data file :
Pajero NA1H25 1 26 3.65 BLADE W/S WIPER
Pajero NA1S25 2 12 65.7 OIL SEAL-T/M CASE
Pajero NA3H25 3 20 14.6 OIL SEAL-DIST
Pajero NA3H25 4 26 10.95 DISC-CLUTCH
Pajero NC3V25 5 13 14.6 FUSIBLE LINK
Pajero ND0000 6 12 3.65 WEATHERSHIELD PKGE-L
Pajero ND1V45 7 10 32.85 SEAL & BOOT KIT
Pajero ND1Z45 8 24 62.05 FUSIBLE LINK
Pajero ND1Z45 9 9 18.25 COVER-HANDLE LH
Pajero ND1Z45 10 6 3.65 PIPE ASSY-OIL
anyone can help ??
Input with operator >> to a std::string will only read a single word.
This means that the first input will read "BLADE" and leave "W/S WIPER" in the input buffer, and the next read will start from there. Eventually, an input operation for a numeric field will try to read letters, and fail to read.
After that the stream is in a bad condition and nothing else is read, even though myfile.eof() is not true (but myfile.fail() is). There you have an infinite loop. See Why is iostream::eof inside a loop condition considered wrong?

getline item returning empty variable

I'm trying to read in a text file and separate the lines into cities and locations. Everything is working for most of the lines, but for I'm getting a
terminate called after throwing and instance of 'std::invalid_argument'
what(): stoi
Aborted (core dumped)
After some investigating, I figured out that it's hanging up on the 2 in Lima, Peru. I could be that the getline function is giving it something it can't handle, but there are instances of exactly the same number in exactly the same position earlier in the document.
...
Hobart, Tasmania: 42 52 S 147 19 E
Hong Kong, China: 22 20 N 114 11 E
Iquique, Chile: 20 10 S 70 7 W
Irkutsk, Russia: 52 30 N 104 20 E
Jakarta, Indonesia: 6 16 S 106 48 E
Johannesburg, South Africa: 26 12 S 28 4 E
Kingston, Jamaica: 17 59 N 76 49 W
Kinshasa, Congo: 4 18 S 15 17 E
Kuala Lumpur, Malaysia: 3 8 N 101 42 E
La Paz, Bolivia: 16 27 S 68 22 W
Leeds, England: 53 45 N 1 30 W
Lima, Peru: 12 0 S 77 2 W
Lisbon, Portugal: 38 44 N 9 9 W
Liverpool, England: 53 25 N 3 0 W
London, England: 51 32 N 0 5 W
Lyons, France: 45 45 N 4 50 E
Madrid, Spain: 40 26 N 3 42 W
...
Here's the section of the code that I think is throwing the error. I can post more if needed, but I think this is the relevant part.
while(is_more_stuff_there(file_to_read))
{
getline(file_to_read, line);
// parse city
index = line.find(':');
city_name = line.substr(0 , line.find(':'));
istringstream position_stream(line.substr(index + 2 , line.find(':')));
cout << city_name << endl;
// initialize an array to store the parsed values from the position_string
string position_array[6];
string item;
int i = 0;
// fill the array, split by spaces
while (getline(position_stream, item, ' '))
{
position_array[i] = item;
i++;
cout << item << endl;
}
cout << position_array[4] << endl;
// initialize the position variables
lat_min = stoi(position_array[0]);
lat_sec = stoi(position_array[1]);
long_min = stoi(position_array[3]);
long_sec = stoi(position_array[4]);
// determine positivity of lats and longs
if (position_array[2] == "S") { lat_min *= -1; lat_sec *= -1; }
if (position_array[5] == "E") { long_min *= -1; long_sec *= -1; }
vertex city(city_name, lat_min, lat_sec, long_min, long_sec);
g.add_vertex(city);
}
There is a non-printing character in your text file, just before the 2 in question. you could find what exactly it is by using od -x (if you're on a unix box). Or simply remove the line and retype it.
One problem that I can see with your code is that the second parameter passed to the substr function seems wrong. It should be the length of the sub-string to extract but that need not coincide with the index of the :. You can simply leave the second parameter out to get the entire remaining sub-string.
std::istringstream position_stream(line.substr(index + 2));
If you only add 1 to index, your code will also parse inputs where there is no space after the colon.
Although not fundamentally wrong, the code could be simplified by using the C++ style extraction operators. You can read in your four fields directly from the stream.
int lat_min, lat_sec, long_min, long_sec;
std::string ns, we;
position_stream >> lat_min >> lat_sec >> ns >> long_min >> long_sec >> we;
Then continue processing them with whatever logic is required.

C++ input data into a struct variables from data file

I have a text file containing names and numbers. The name or the string contains 15 chars and I need to put it to the string. I'm working with structures.
struct grybautojas{
string vardas;
int barav, raudon, lep, diena;
}gryb[100];
After that, there are simple calculations which is done right, the problem is, it only reads everything once. After taking a first "box" of information, it just stops. Everything else in the result file is either blank as a string or 0 as an integer.
Here's my input function:
void ivedimas(){
char eil[16];
int b,r,l;
inFile >> n;
inFile.ignore();
for(int i=0;i<n;i++){
inFile.get(eil,15);
gryb[i].vardas=eil;
inFile >> gryb[i].diena;
gryb[i].barav=0, gryb[i].raudon=0, gryb[i].lep=0;
for(int m=0;m<gryb[i].diena;m++){
inFile >> b >> r >> l;
gryb[i].barav+=b, gryb[i].raudon+=r, gryb[i].lep+=l;
}
inFile.ignore();
}
inFile.close();
}
And here's the file containing data:
4
Petras 3
5 13 8
4 0 5
16 1 0
Algis 1
9 6 13
Jurgis 4
4 14 2
4 4 15
16 15 251
1 2 3
Rita 2
6 65 4
4 4 13
What's the problem?
inFile.get(eil,15);
Rita 2
Petras 3
00000000011111
12345678901234
I don't count 15, I count 14. Also, some of your lines seem to have a space at the end. You should rewrite your input logic to be much more robust. Read lines and parse them.
This line:
inFile.get(eil,15);
is reading the number that follows the name.
When you try to read the number (3 in your example), you get the next one (5) instead.