While loop reads extra line

So I searched the forum and it didn't have what I needed exactly.

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
   while(Customer.good())
    {
   Customer.getline(Name,25,'~');
   Customer>>StartSalary>>Age;   

   if (StartSalary>0&&StartSalary<15000) 
   {BaseTaxes=0;
    ExcessTaxes=(StartSalary-0)*.15;NetSalary = StartSalary - (BaseTaxes + ExcessTaxes);}
   else if (StartSalary>=15000&&StartSalary<30000)
   {BaseTaxes=2250;
    ExcessTaxes=(StartSalary-15000)*.16;NetSalary = StartSalary - (BaseTaxes + ExcessTaxes);}
   else if (StartSalary>=30000&&StartSalary<50000)
   {BaseTaxes=4650;
    ExcessTaxes=(StartSalary-30000)*.18;NetSalary = StartSalary - (BaseTaxes + ExcessTaxes);}
   else if (StartSalary>=50000&&StartSalary<80000)
   {BaseTaxes=8250;
    ExcessTaxes=(StartSalary-50000)*.20;NetSalary = StartSalary - (BaseTaxes + ExcessTaxes);}
   else 
   {BaseTaxes=14250;
   ExcessTaxes=(StartSalary-80000)*.25;NetSalary = StartSalary - (BaseTaxes + ExcessTaxes);}
 
   cout<<Name<<"\t"<<StartSalary<<"\t"<<Age<<"  ";
  cout<<BaseTaxes<<"\t   "<<ExcessTaxes<<"\t   "<<NetSalary;

   
   }
   
   Customer.close();

}


So when I output this code from the file I get an extra line minus char Name.

How do i cut off the loop so that doesn't happen.

Thanks
First things first:

Try to use a switch. The else ifs get really messy and make your code messy.

1
2
3
4
5
6
7
8
9
char unit = 'a';
switch (unit){
	case 'a':
		// code goes here;
	case 'b':
		// different code goes here;
        default:
                 // default action goes here;
			}
Last edited on
What is the line it is giving you that you don't want?
In order for him to use a switch/case he will need to get the extension for gcc that allows for the sequential ranges that Visual Basic allows.

case 1...3:
//Do Something
break;
case 4...6:
//Do Something
break;
default:
//Do the Default
break;
consider checking if getline() or operator>> fails. As written, the code goes on to do things to Name and Age even after the end of file.
incidentally, "while(file.good())" is almost always wrong.
Last edited on
This happens in c++ when the first item from the .txt file is brought in with getline() and the last item is brought in with a << instead of a getline(). Your buffer retains the \n character when it reads in the last real name. then it thinks it is still indata.good and will output that last dreaded line.

The following code works in this scenario and should help -
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include <fstream>

using namespace std;

int main()
{
    char Name[25];
    int StartSalary, Age;
    ifstream indata;

    indata.open("fix.txt");
    indata.getline(Name,25,'~');
    while(indata.good())
    {
        indata>>StartSalary>>Age;
        cout<<Name<<"\t"<<StartSalary<<"\t"<<Age<<"  "<<endl;
        indata.getline(Name,25,'~');
    }

   indata.close();
}


here was my fix.txt
1
2
3
john star ~ 4500 20
bill gates ~ 4600 30
kathy giulds ~ 4800 40

Last edited on
Select a program1


Name            Start Salary  Age  BaseTaxes    ExcessTaxes     NetSalary
Richard Smith   12000.5 35  0      1800.07         10200.4
Jack Jones      25000.4 26  2250           1600.06         21150.3
Alice Jones     41234.1 45  4650           2022.14         34562
Jerry Muir      70002   39  8250           4000.4          57751.6
Boris Baker     12345.3 54  0      1851.79         10493.5
        12345.3 54  0      1851.79         10493.5Press any key to continue . .
.


So the additional info at the bottom is what I want to delete. iamk2, I tried what you said by placing the getline at the end, but then it fails to read the file completely.

Why is (file.good()) always wrong?

Thanks for all the help.
1. Did you leave the one before the loop out ? You need that one also!!
2. .good always works for me!

This is the cleanest way I know to solve the problem and from seeing you output this is what is happening.
Last edited on
Thanks it worked when I placed the get line to the end of the file.
What I call an unclean and waste of resources fix would be in the code as follows. The one I gave you above is better all around. But just more info for you here.

First I will explain - Each time you read in with your getline - char[0] will actually = the first char in the name.
Then from there on char[0] will be '\n'. So by testing after each read and before each cout with an if statement you can catch the first null char in char[1] and break the loop before it prints the dreaded erroneous last line. But each line in your .txt file cant have any preceding blanks before the name.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
#include <fstream>

using namespace std;

int main()
{
    char Name[25];
    int StartSalary, Age;
    ifstream indata;
    indata.open("fix.txt");

    while(!indata.eof())
    {
        indata.getline(Name,25,'~');
        if (Name[1]==0)  //or if(Name[1]==NULL)
            break;
        indata>>StartSalary>>Age;

        cout << Name << StartSalary <<Age<<endl;
    }
   indata.close();
}


Note I used !indata.eof() instead of indata.good() but either works just fine. When someone says standard function commands don't work most of the time, what they are really saying is that people are misunderstanding something in the way the code works - Face it - the machine is one's and zero's - Hate to say it but when coding does not work it is the programmers fault. Not to say I have not cursed the machine for not working properly but in the end - its always a person fault.
Last edited on
iamk2,

Thank you for the insight. It's nice to know why it was not running correctly, and not just how to fix it.

Thanks again.
thanks!
masschamber wrote:
Why is (file.good()) always wrong?
while(file.good()) is wrong because istream::good() is not intended for use in a while loop condition. Same goes for while(!file.eof()).

Typical misuse of these functions is code such as
1
2
3
4
5
while(file.good()) // or while(!file.eof())
{
    cin >> data;  // or any other input operation
    // process data
}

The typical symptom of this is what people report as "last line was repeated" or "while loop reads extra line". It did not actually read the extra line. It ran off the end of file, the input operation failed, and the value in the variable 'data' was not changed: it was the same value that was obtained on the previous loop iteration. Only the second time around after the end of file the eof()/good() gets a chance to break the loop.

In this case, you have two kinds of input operations: istream::getline, which writes a zero-length C string into the output array when it fails and istream::operator>> which doesn't get a chance to execute after getline()'s failure, so the contents of StartSalary and Age remain unmodified after you run off the end of file.
As you reported,
I get an extra line minus char Name


Natural C++ input loop is
1
2
3
4
while( /* input operation, such as cin >> data */ )
{
    // process data
]

which would be in your case
1
2
3
4
5
while( Customer.getline(Name,25,'~')
       && Customer >> StartSalary >> Age )
{
    // calculate taxes and print the results
}


(note that istream::getline() will pick up the trailing endline from the end of the last line, as well as the space before the '~' - you may skip the former with ws:
1
2
3
4
5
6
while( Customer >> ws 
       && Customer.getline(Name,25,'~')
       && Customer >> StartSalary >> Age )
{
    // calculate taxes and print the results
}

If that input operation gets too complex, turn your record into a struct with its own input/output operators, so the loop stays simple.

Also note that C++ supports strings, it may be helpful to turn Name into a string, in which case the input will be getline(Customer, Name, '~') )
Last edited on
Glad someone else chimed in! Even though both of my solutions work, I really believed there had to be a more correct way to accomplish this task. Using a read in statement twice just to get the desired outcome is still not great. Reminds me of having to turn the key twice to get the car to start.

So after reading cubbi's post I tried his info and it gave the correct results -

?. there is a ws put in with no exact explanation of what it is.

After reading the entire post I have come to assume that it stands for white space.
and that it is part of c++ ??????

I have to read in from txt files both strings an int's with 9 to 10 items per line. Could I get one detailed example using just the small data in the above given .txt file

for
turn your record into a struct with its own input/output operators


unsure what is meant by that
also one more question for clarity

I had the need to authenticate that when the user was asked to input an int value that for any and all mistypes the program would catch it and let the user know his int was "dr23" or "23d" or "forg" and not a correct int like 7.

I came up with this which works

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 bool        good_int(string& userchoicestr,int& userchoiceint){

    getline(cin,userchoicestr);
    stringstream convert(userchoicestr);
    if (convert >> userchoiceint)
        {
            if (!convert.eof())
                {
                    display_incorrect_input(userchoicestr);
                    return false;
                }
        }
    else
        {
            display_incorrect_input(userchoicestr);
            return false;
        }
    return true;
}


Not using inside a while as above so I assume .eof is ok to use here but was wondering if there was a more efficient or globally used method.
Topic archived. No new replies allowed.