7
int x=0;
string fullname = "";
float salary;
float payincrease;
float newsal;
float monthlysal;
float retroactive;
while(x<3){
    cout << "\n What is your full name?";
    cin >> fullname;
    cout << "\n What is your current salary? \t";
    cin >> salary;
    cout << "\n What is your pay increase? \t";
    cin >> payincrease;
    newsal = (salary*payincrease)+salary;
    monthlysal = newsal/12.00;
    retroactive = (monthlysal*6)-(salary/2);
    cout << "\n" << fullname << "'s SALARY INFORMATION";
    cout << "\n New Salary \t Monthly Salary \t Retroactive Pay";
    cout << "\n \t" << newsal << "\t" << monthlysal << "\t" << retroactive;
    x++;
}

My loop doesn't seem to stop for every time cin is asked, and instead instantly executes the loop 3 times on its own. How do I get it to stop when input is asked?

smskelley
  • 161
  • 1
  • 7
user1647490
  • 91
  • 1
  • 1
  • 2
  • 5
    `cin` stops at spaces. It'll work fine if you enter one word at a time. Otherwise, use `std::getline`. – chris Sep 04 '12 at 22:35
  • You must never write an input operation that's not immediately captured inside a boolean context. Otherwise there's no telling how your program might flow. No point looking any further. – Kerrek SB Sep 04 '12 at 22:36
  • 2
    @chris, `cin` itself doesn't "stop" specifically at spaces; `operator>>(istream&,string&)` does, by default. – eq- Sep 04 '12 at 22:37
  • @eq-, I appreciate your pedancy. You are correct, of course. `cin` is just an object. – chris Sep 04 '12 at 23:03
  • Do you try to input spaces in your full name? If so, the first word (given name) is read as the full name, then the second word (surname) is converted to the salary — and fails, but you don't check the conversion... – Jonathan Leffler Sep 05 '12 at 00:26
  • 2
    @chris *pedantry (since you appreciate it) --couldn't resist. – Matt Phillips Sep 05 '12 at 01:01
  • @MattPhillips, Something seemed a bit odd when I was typing that... Not sure why I did it. – chris Sep 05 '12 at 01:03

3 Answers3

12

If the input stream isn't empty when you call cin, then cin uses the data already in the buffer instead of waiting for more from the user. You're using the extraction operator, so when cin is sending values to your variables, it skips leading whitespace in the buffer and stops on the next whitespace.

Put a breakpoint on this line:

cout << "\n What is your current salary? \t";

Run the program, and enter Bob Smith. When you hit the break point, hover your cursor over your string fullname. You'll see it stores only "Bob" not "Bob Smith". "Bob Smith" got put into the buffer, but when you use cin with the extraction operator, it skips any leading whitespace, puts the next value it finds into your variable, then stops on the next whitespace. To demonstrate this, try running this:

#include <iostream>
#include <string>
using namespace std;
int main()
{
    string str1,str2;
    cin >> str1;
    cin >> str2;
    cout << str1 << " " << str2 << "\n\n";
    return 0;
}

If you type in "Bob Smith", it will take your input only one time, even though you call cin twice. However, you'll see that both "Bob" and "Smith" got captured in the strings str1 and str2.

Therefore, you can conclude that cin stops populating your string fullname when it gets to the space between Bob and Smith. On your next call to cin, the buffer still contains "Smith", so instead of taking more input from the user, it attempts to fill your variable salary with "Smith". Obviously this isn't want you want to do. You can call flush and ignore on cin to wipe out the buffer before every time you use cin, or instead you could fix your logic and use getline to take in the full name, including spaces.

To fix your problem, all you need to do is use getline instead of cin >>, so replace this line:

cin >> fullname;

with this:

getline(cin,fullname,'\n');

Secondly, you're using a while loop to execute a set of actions a specific number of times. That's typically something you'd use a for loop for.

As an aside, you could also write tiny input validation loops that can help you debug or otherwise avoid attempting to put invalid input into your variables (such as "Smith" into a float). Something like this could work:

for(;;)
{
    if(cin >> salary)
        break;
    cin.clear();
    cin.ignore(INT_MAX,'\n');
}

Note that cin returns a value, so you can use it in an if statement. If it gets valid input, it will return true. If not, it will return false. To make it more explicit, you could also just use a normal call to cin without the if statement, and then check if cin.good(), which amounts to basically the same net effect. If you're not using Visual Studio and get an error about INT_MAX, you might need to #include limits.h to resolve it.

derpface
  • 1,611
  • 1
  • 10
  • 20
  • Note that when using getline(), you need to be careful about whitespace remaining in the input buffer. In particular, any '\n' characters will cause the next use of `operator<<()` to appear like it is ignored. – Code-Apprentice Sep 05 '12 at 01:17
  • @Code-Guru, you're referring to cin.getline right? There is no danger of this in the getline I'm using. cin<< discards leading whitespace, including '\n', so it wouldn't make a difference. The only time it would matter is if you called cin.getline afterwards, because getline accepts just a '\n' as input, whereas cin.get will fail. But I'm not calling cin.getline. – derpface Sep 05 '12 at 02:01
  • grr...you are probably right. It's been too long since I've programmed C++ on a regular basis. I guess I need to review this stuff before I answer questions like this... – Code-Apprentice Sep 05 '12 at 02:03
  • 1
    Yeah, cin has a few weirdnesses and doesn't get used enough to really matter once you're past learning to program in a console window. – derpface Sep 05 '12 at 02:19
  • Exactly. And I apparently I am currently confused about which functions case which weirdnesses... – Code-Apprentice Sep 05 '12 at 02:21
  • In the 'Bob Smith' example, in my case I got the print 'Bob Smith' and 'Bob Smith'. So in my g++ (4.4.7), cin gets the whole line but still holds it so not taking the second `cin>>`. Can I fix it without using getline()? – Chan Kim Aug 19 '16 at 01:07
5

That occurs if you input a char where an int is expected.

Use cin.clear(); and cin.ignore(numeric_limits<streamsize>::max(), '\n'); to limit an input to int's only.

Other than that, it won't skip if the correct data type is put in.

#include <string>
#include <iostream>
#include <limits>
using namespace std ;



int main(void)
{


    int x=0;
    string fullname = "";
    float salary;
    float payincrease;
    float newsal;
    float monthlysal;
    float retroactive;

    while(x<3)
    {
        cout << "\n What is your full name?";
        cin >> fullname;
    cin.ignore( 1000, '\n' );

        cout << "\n What is your current salary? \t";
        cin >> salary;
    cin.clear();
    cin.ignore(numeric_limits<streamsize>::max(), '\n');

        cout << "\n What is your pay increase? \t";
        cin >> payincrease;
    cin.clear();
    cin.ignore(numeric_limits<streamsize>::max(), '\n');

        newsal = (salary*payincrease)+salary;
        monthlysal = newsal/12.00;
        retroactive = (monthlysal*6)-(salary/2);
        cout << "\n" << fullname << "'s SALARY INFORMATION";
        cout << "\n New Salary \t Monthly Salary \t Retroactive Pay";
        cout << "\n \t" << newsal << "\t" << monthlysal << "\t" << retroactive;
        x++;
    }


      cout<<" \nPress any key to continue\n";
      cin.ignore();
      cin.get();

   return 0;
}
Software_Designer
  • 8,490
  • 3
  • 24
  • 28
0

Check your variable types, I noticed mine accepting a digit instead of a character, had the same problem (not stopping, loop just kept going on).

> std::cin >> this->controls.button

> DETOX_NUMBER button; // (int) 

Change to:

> char button;
Valtsuh
  • 11
  • 3