0

Why does my code skip the last question when I put to much info in for the fist one? What am I doing wrong?

const int SIZEC =31;
char phrase[SIZEC];
cout << " Provide a phrase, up to 30 characters with spaces. > " << endl;
cin.getline(phrase, SIZEC);
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cout << " The phrase is: " << phrase << endl;
cout << endl;


cout << " Using sring Class Obects " << endl;
cout << "--------------------------" << endl;
cout << endl;

string leter;
cout << " Provide a single character > " << endl;
cin >> leter;
cout << " The single character is: " << leter << endl;
cout << endl;

If the code before this is needed tell me and I'll add it.

Katie Stevers
  • 135
  • 1
  • 1
  • 13

2 Answers2

1

Use std::string::resize as a workaround.

string phrase;
getline(cin, phrase);
phrase.resize(30);    // phrase will be reduced to 30 chars

string letter;    // better to use char letter
cin >> letter;
letter.resize(1);
Shreevardhan
  • 12,233
  • 3
  • 36
  • 50
  • The first one is a cstring and it has to stay that way... I probably should've added that too. When I try 'phrase.resize(30)' I get an error. I assume it is because it is a cstring. – Katie Stevers Feb 02 '17 at 05:53
0

The main problem is that getline behaves differently in two cases:

  1. If at least SIZEC characters are read and there is no newline character among them (e.g. there should be at least SIZEC+1 bytes to store the data read), it stops reading and sets so-called failbit status bit on the stream, which means "I have failed to read something, so input stream is probably incorrect". Quoting cplusplus.com:

    The failbit flag is set if the function extracts no characters, or if the delimiting character is not found once (n-1) characters have already been written to s.

  2. If newline character is encountered, failbit is not set and the newline character is succesfully read and ignored by getline.

What happens next is more interesting: extraction functions (all of them, I assume) fail immediately if the input stream is bad() (that is, either failbit, badbit, or eofbit are set on the stream). In particular, if previous extraction operation failed, all subsequent will fail as well. So, basically, if first line of the input cannot be fitted in your phrase array, then cin becomes "bad" and all further read operations do nothing.

You can override that behavior by manually resetting the failbit after calling getline like this: cin.clear(); Following read operations will succeed until another one fails.

In your particular case, I assume that you want to read the first line regardless of the length, and then a second line. I that case, I think you should to first check whether getline failed (by checking cin.failbit() or cin.good()) and then either do nothing (if it did not and there is no need in reading extra newline) or resetting the failbit and ignoring characters till the first newline. Something like this:

#include <iostream>
#include <limits>
#include <string>

using namespace std;

int main() {
    char buf[5];
    cin.getline(buf, sizeof buf);
    if (!cin) { // operator ! is overloaded for `istream`, it's equal to `good()`
        // If stream is bad: first line of the input was truncated,
        // and following newline character was not read.

        // Clear failbit so subsequent read operations do something.
        cin.clear();

        // Read remaining of the first line.
        cin.ignore(numeric_limits<streamsize>::max(), '\n');
    }
    // At this point, first line of the input is consumed
    // regardless of its length
    int x;
    cin >> x;
    cout << "String: |" << buf << "|\n";
    cout << "x: " << x << "\n";
}

You can read more on StackOverflow here and there.

However, if there is no reason to use C-style string together with istreams, I'd suggest you using string and std::getline instead (like in Shreevardhan's answer); it will produce cleaner code and there will be no extra cases.

Community
  • 1
  • 1
yeputons
  • 8,478
  • 34
  • 67