Aradhya
Aradhya

Reputation: 53

Why is my small c++ code behaving unexpectedly?

// using structures
#include <iostream>
#include <string>
using namespace std;

struct playerinfo
{
    string name;
    int level;
};

int main()
{
    playerinfo arr[5];
    for (int i = 0; i < 5; i++)
    {
        cout << " enter name for player " << i << endl;
        getline(cin, arr[i].name, '\n');
        cout << " and level \n";
        cin >> arr[i].level;
    }
    for (int i = 0; i < 5; i++)
        cout << "the level of player " << arr[i].name << " is " << arr[i].level << endl;
}

I am reading a book on c++ syntax and I am practicing. I want the code to behave such that the code asks the user to fill in the names of the players and the levels and then the code prints them all. But it is not behaving like this. when I run the code and enter the name of the player say " tom cat" then the code asks the level and I print an integer say "100", and then unexpected things start happening, the reason of which, I am unable to understand. Can you please help? edit- few people have asked me to elaborate what "unexpected things" start happening. The unexpected thing is that when I type in the name of the player and the level of player 0, the next output on the screen is " enter name for player 1 and level " whereas I expect that it should only output "and level" after I enter the name of the player 1.

Upvotes: 1

Views: 162

Answers (3)

Dietmar K&#252;hl
Dietmar K&#252;hl

Reputation: 153840

When switching from formatted input using operator>>(), e.g., in cin >> arr[i].level and unformatted input, e.g., using std::getline() you need to be aware of whitespace potentially waiting in the input: the formatted input of an integer stops as soon as it finds a whitespace, e.g., a newline. On the other hand, std::getline() will stop as soon as it find a newline! So you receive an empty line. The fix is to skip leading whitespace when switching to unformatted input, e.g.:

std::getline(std::cin >> std::ws, arr[i].name);

The manipulator std::ws skips leading whitespace when using it with an std::istream.

You should also always verify that your inputs were successful before using them: if any input fails, the stream stops functioning and converts to false:

if (std::cin >> arr[i].level) {
    // process the data
}
else {
    // report that the input is wrong and bail out
}

Upvotes: 6

Vlad from Moscow
Vlad from Moscow

Reputation: 310980

Include header

#include <limits>

and before this statement

    getline(cin, arr[i].name, '\n');

insert statement

cin.ignore( numeric_limits<streamsize>::max() );

The problem is that after statement

cin >> arr[i].level;

the input buffer will keep the new line character ( '\n') after the user pressed Enter and the next getline function will read empty string before this new line character.

Upvotes: 1

Joseph Mansfield
Joseph Mansfield

Reputation: 110658

When you type in the level and press enter, you are essentially inputting 100\n. The in >> arr[i].level will extract the number 100 and put it in arr[i].level, stopping because it hit the newline, but it won't extract the newline itself. The newline is left in the input stream! The next iteration will begin, and getline will see that there is already some available input to read, it will attempt to read a line up to the next \n character. As we know, the next \n is the first character left in the input, so getline will read an empty string. From now on, your program is in a screwed up state.

A quick way to get around this is to discard characters from the input after reading the level up until and including the newline character using ignore:

cin >> arr[i].level;
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

This would allow the user to input 100foobar and it would be interpreted as just 100. That might be what you want or it might not be. If you want to accept/reject some other formats, I'll leave that up to you.

Upvotes: 1

Related Questions