3

I'm very new to programming, and I'm having trouble using getline in a while loop. When I cout the course variable the first letter is missing. Getting rid of cin.ignore sends it into an infinite loop.

Here's what I have so far:

#include <iostream>
#include <string>
using namespace std;
int main (){
   string answer = "Yes";
   string course;

   while (answer == "Yes"){
      cin.ignore();
      cout<< "Enter a course name: ";
      getline (cin, course);
      cout<< course << endl;

      cout<< "Continue ('Yes' or 'No')? ";
      cin>> answer;
      cout<< answer << endl;
   }

   return 0;
}
hccc
  • 31
  • 1
  • 2
  • works fine for me - https://ideone.com/Qk9ZCx without `cin.ignore()` – Abhishek Keshri Apr 26 '18 at 22:37
  • maybe you are entering `course` and `No` on the same line? – Abhishek Keshri Apr 26 '18 at 22:41
  • @AbhishekKeshri it **does not** work without the ignore if you try to use `getline` again after `cin`: [ideone](https://ideone.com/CR5rnD) – scohe001 Apr 26 '18 at 22:43
  • ahh, i see!!!!! – Abhishek Keshri Apr 26 '18 at 22:44
  • Recommended reading: [Why does std::getline() skip input after a formatted extraction?](https://stackoverflow.com/questions/21567291/why-does-stdgetline-skip-input-after-a-formatted-extraction) – user4581301 Apr 26 '18 at 22:57
  • General rule of thumb: Place ignore after an operation that you know will leave data that needs to be ignored in the stream. Placing a preemptive `ignore` before an operation just to make sure there is nothing in the buffer often discards data you do want. – user4581301 Apr 26 '18 at 23:10

3 Answers3

4

Move the ignore to the bottom of your loop. It's there to remove the newline character that the cin >> operator leaves in the buffer, so you only need it after you've used cin >>.

You should also pass arguments to ignore to ignore everything until you hit a newline in case they've entered more than just "Yes" or "No" on the line. You can do that with:

cin.ignore(numeric_limits<streamsize>::max(), '\n');

See a working example here: ideone.

scohe001
  • 13,879
  • 2
  • 28
  • 47
  • for the basic question asked, `cin.ignore()` is not needed at all. `getline` extracts and discards the newline – jwm Apr 26 '18 at 22:53
  • @jwm `getline` does indeed, but the extraction operator (`cin >>`) doesn't, [which is why the ignore is necessary](https://stackoverflow.com/questions/10553597/cin-and-getline-skipping-input). – scohe001 Apr 26 '18 at 22:59
  • yes, I notice the mixing of styles in @Gil Bates answer ... a much better answer – jwm Apr 26 '18 at 23:00
2

The problem that I see is when you remove cin.ignore() you get interaction as follows:

Enter a course name: Math

Math

Continue ('Yes' or 'No')? Yes

Yes

Enter a course name:

Continue ('Yes' or 'No')? Yes // etc, etc...

The second time it does not prompt you for class input. This is because the Enter/Return you use to submit the info is getting extracted by getline(), which stops at the first '\n' character it sees.

One way to fix it is use cin.ignore(), after your custom input. Mind that if reading from file, you should end the line after class input to get the same result as here.

  while (answer == "Yes"){
                                     // REMOVE cin.ignore() FROM HERE
      cout<< "Enter a course name: ";
      getline (cin, course);
      cout<< course << endl;

      cout<< "Continue ('Yes' or 'No')? ";
      cin>> answer;
      cout<< answer << endl;

      {    // THIS IS MORE EFFICIENT
           cin.ignore();                // ADD cin.ignore() HERE TO DISCARD '\n'
      }

      {   // THIS WORKS BETTER FOR HUMAN INPUT
          string dummy;
          getline (cin, dummy)          
      }
  }
Community
  • 1
  • 1
Kostas
  • 3,822
  • 11
  • 28
  • 2
    Good answer, but is intolerant of human error. What if there is a typo and the user adds a space before hitting enter? – user4581301 Apr 26 '18 at 23:02
  • That’s an excellent point. I’d say that getline is a function that is suitable for reading files and not really for human input though. An alternative would be calling getline again instead of cin.ignore() but no one wants to do that :) – Kostas Apr 26 '18 at 23:06
  • 1
    Getline is ok for reading cin, because the user naturally inputs line by line. However, ALL user input should be parsed for errors first. – Brady Dean Apr 27 '18 at 02:59
2

If you use getline, stick to getline. Mixing it with stream operations will easily mess things up.

#include <iostream>
#include <string>

int main() {
  std::string answer = "Yes";
  std::string course;

  while (answer == "Yes") {
    do {
      std::cout << "Enter a course name: ";
      std::getline(std::cin, course);
    } while (course == "");

    std::cout << course << '\n';

    do {
      std::cout << "Continue ('Yes' or 'No')? ";
      std::getline(std::cin, answer);
    } while (answer != "Yes" && answer != "No");

    std::cout << answer << '\n';
  }
}
Brady Dean
  • 2,150
  • 2
  • 19
  • 38