Jump to content

C++ help - shouldn't be too hard.

My C++ program is supposed to read the info from a .txt file and read all the info, but the while loop that reads the info file (data.txt) goes on forever. Can someone explain why? I've been stumped for a while now. 

using namespace std;
#include <iostream>
#include <fstream>
#include <iomanip>
#include <string>
int main()
{
    string ssn,name,attendance;
	string filename = "data.txt";
    double lab,pa,quiz,midterm,final,average;
    fstream data;
    data.open(filename);
    if(data.is_open())
        {
            cout << "Error opening file.";
            system("pause");
            return 0;
        }
    cout.setf(ios::fixed | ios::showpoint);
    cout.precision(1);
    
    while(!data.eof()){
    getline(data,ssn);
    getline(data,name);
    getline(data,attendance);
    data >> lab >> pa >> quiz >> midterm >> final;
    lab = lab * .15; // weights average
    pa = pa * .25;
    quiz = quiz * .15;
    midterm = midterm * .2;
    final = final * .25;
    average = lab + pa + quiz + midterm + final;
	cout << left << setw(12) << ssn << name << left << setw(25) << name << left
		<< setw(3) << attendance << right << setw(7) << attendance << endl;
    }
    
    
            
    system("pause");
    return 0;
}

Here's data.txt:

111-11-1111
John Doe
G
85 90 87 95 89
111-11-1112
Jane Doe
P
78 65 71 74 75
111-11-1113
John Smith
G 
45.0 43.0 44.0 45.0 43.0

Please help. I may need a little help writing to the file, but first things first.

qυoтe мe pleaѕe!

Me at the Apple store: "So how fast is this little macbook?"

Apple employee: "Cheetah Fast. Lightning Fast. It's Really, really, fast."

Link to comment
https://linustechtips.com/topic/978272-c-help-shouldnt-be-too-hard/
Share on other sites

Link to post
Share on other sites

Just to be clear, you're getting output from your loop but the loop doesn't end?

[Out-of-date] Want to learn how to make your own custom Windows 10 image?

 

Desktop: AMD R9 3900X | ASUS ROG Strix X570-F | Radeon RX 5700 XT | EVGA GTX 1080 SC | 32GB Trident Z Neo 3600MHz | 1TB 970 EVO | 256GB 840 EVO | 960GB Corsair Force LE | EVGA G2 850W | Phanteks P400S

Laptop: Intel M-5Y10c | Intel HD Graphics | 8GB RAM | 250GB Micron SSD | Asus UX305FA

Server 01: Intel Xeon D 1541 | ASRock Rack D1541D4I-2L2T | 32GB Hynix ECC DDR4 | 4x8TB Western Digital HDDs | 32TB Raw 16TB Usable

Server 02: Intel i7 7700K | Gigabye Z170N Gaming5 | 16GB Trident Z 3200MHz

Link to post
Share on other sites

10 hours ago, Natsoup said:

My C++ program is supposed to read the info from a .txt file and read all the info, but the while loop that reads the info file (data.txt) goes on forever. Can someone explain why? I've been stumped for a while now.

Like already mentioned by @mail929, you're actually aborting the program when the file successfully opens and continuing when it does not. So you're always working with an unopened file.

if(!data.is_open()) // ! added to invert logic 
{
	cout << "Error opening file.";
  	system("pause");
  	return 0;
}

 

Secondly - you're falling into the age-old trap of eof checking before a read, which is wrong:

//Imagine the previous iteration of the loop read the last thing in the file...
//We're at the end of the file now but EOF is not set yet !...
while(!data.eof())  //...so we enter the loop again...
{
    getline(data,ssn); //...and try to read, ONLY NOW does EOF get set...
    getline(data,name); //...but we continue to read and work with bogus values...
    getline(data,attendance);
    data >> lab >> pa >> quiz >> midterm >> final;
  
  	//<snip>

 

Even if it were to work, it's not a very robust way of doing things. You're making too much assumptions about the file format. You test for EOF and when not at EOF yet, you assume there's 4 more lines there. Do your reading first and test stream validity *after* the read before continuing:

while(1)  //Loop forever, break manually when you need to exit the loop
{
    getline(data,ssn); 
    getline(data,name); 
    getline(data,attendance);
    data >> lab >> pa >> quiz >> midterm >> final;
  
    if (!data)
    {
    	//Stream became invalid - test for reason here...
	if (data.eof())
        {
         	//End of file reached, discard data read in this loop...
          	//because it is invalid and exit loop.
          	break;
        }
      
      	//If not EOF - test for other errors such as a type... 
      	//mismatch during extraction...
    }
    else
    {
     	//Stream still valid, process data we just read...  
    }
}

 

 

Link to post
Share on other sites

15 hours ago, 2FA said:

Just to be clear, you're getting output from your loop but the loop doesn't end?

Correct. makes sense now - I wasn't actually opening the file correctly.

 

5 hours ago, Unimportant said:

Secondly - you're falling into the age-old trap of eof checking before a read, which is wrong:

Sadly, I'm not very advanced in programming (if you couldn't tell :P) So I really don't understand what you mean. My teacher taught the class this way, so I've been doing it like that. It's definitely not the best way to do things. This assignment is designed to practice good structure in my code, though. But using !data - would that check that data exists, so 1 if data doesn't exist, but 0 if it does? Or is it that !data would check if there's anything left in the file, and if there is something left, it outputs 0, so the if statement's contents aren't used? After writing this, I think it's the latter, but I don't know for sure. I'm going to write my program using this method now. Expect an update sooner or later :) 

qυoтe мe pleaѕe!

Me at the Apple store: "So how fast is this little macbook?"

Apple employee: "Cheetah Fast. Lightning Fast. It's Really, really, fast."

Link to post
Share on other sites

 while (1) {
   
      getline(data, ssn);
      getline(data, name);
      getline(data, attendance);
      data >> lab >> pa >> quiz >> midterm >> final;

      if (!data)
      {
         cout << "You are seeing this because something went wrong. \n";
         if(data.eof())
         {
            cout << "End of file reached. \n";
            break;
         }
      }
      else
      {
         lab = lab * .15; // weights average
         pa = pa * .25;
         quiz = quiz * .15;
         midterm = midterm * .2;
         final = final * .25;
         average = lab + pa + quiz + midterm + final;
         cout << left << setw(12) << ssn << name << left << setw(25) << name << left
            << setw(3) << attendance << right << setw(7) << attendance << endl;
      }
      
   }

@Unimportant I thought this would work... seemed to make sense.

It loops infinitely on the cout << "You are seeing this because something went wrong. \n";

that's also the location I'm confused about atm - the if !data :/ 

qυoтe мe pleaѕe!

Me at the Apple store: "So how fast is this little macbook?"

Apple employee: "Cheetah Fast. Lightning Fast. It's Really, really, fast."

Link to post
Share on other sites

35 minutes ago, Natsoup said:

It loops infinitely on the cout << "You are seeing this because something went wrong. \n";

that's also the location I'm confused about atm - the if !data :/ 

The eof flag gets set when something tries to read past the end of file, because of how the getline and >> functions work this will never happen. You need to use .good() or cast to bool instead of .eof().

1474412270.2748842

Link to post
Share on other sites

On 10/2/2018 at 3:46 PM, fizzlesticks said:

The eof flag gets set when something tries to read past the end of file, because of how the getline and >> functions work this will never happen. You need to use .good() or cast to bool instead of .eof().

Same result with .good(). This is... hard.

qυoтe мe pleaѕe!

Me at the Apple store: "So how fast is this little macbook?"

Apple employee: "Cheetah Fast. Lightning Fast. It's Really, really, fast."

Link to post
Share on other sites

3 hours ago, Natsoup said:

Same result with .good(). This is... hard.

After reading final using the extraction operator >> there is a newline that does not get extracted by operator >>. Extract it manually. Here's a little demo program:

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

int main()
{
    	string ssn, name, attendance;
	string filename = "data.txt";
    	double lab, pa, quiz, midterm, fnl, average;  //final changed to fnl because it's a c++11 keyword.
    	fstream data;
    	data.open(filename);
    	if(!data.is_open())
        {
        	cout << "Error opening file.\n";
            	system("pause");
            	return 1;
        }
    	cout.setf(ios::fixed | ios::showpoint);
    	cout.precision(1);
    
    	while(1)
	{
    		getline(data,ssn);
    		getline(data,name);
    		getline(data,attendance);
    		data >> lab >> pa >> quiz >> midterm >> fnl;

		string dummy;
		getline(data, dummy); //extract newline character following final

		if (data)
		{
			cout << "Record:\n";
			cout << "ssn: " << ssn << '\n';
			cout << "name: " << name << '\n';
			cout << "attendance: " << attendance << '\n';
			cout << "grades: " << lab << ' ' << pa << ' ' << quiz << ' ' << midterm << ' ' << fnl << '\n';
			cout << "-----------------------------\n"; 
		}
		else
		{
			cout << "Reading failed:\n";
			cout << "badbit: " << data.bad() << '\n';
			cout << "failbit: " << data.fail() << '\n';
			cout << "eofbit: " << data.eof() << '\n';
			return 2;
		}
    	}
}

 

Do note that in a proper program one would read all 4 lines using getline and extract the grades using a stringstream, which is much cleaner.

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×