-1

I am trying to implement a pause function in C++, but it is looping forever.

I am using macOS but I am trying to create a pause function that will work in any system... I believe my cin >> is not capturing '\n' or '\r' from the keyboard and it is looping forever.

void Transferencia::pause() {
    char enter = 0;
    while(enter != '\n' && enter != '\r') {
        cout << "(Press Enter to Continue...) ";
        cin >> enter;
    }
    cin.clear();
}

I want to pause my program until user press the key "enter". But even when I press "enter/return" it keeps looping...

  • [MAC](https://en.wikipedia.org/wiki/MAC_address) means something entirely different from Mac. – tadman Sep 23 '19 at 16:22
  • 2
    When `enter` can be equal to `'\n'` **and** equal to `\r`? – Jarod42 Sep 23 '19 at 16:22
  • 1
    Hint: `||` -> `&&`. – tadman Sep 23 '19 at 16:23
  • Have you tried checking the value of `enter` ? Just so you can "hand-check" your `while` conditions? Also, think for a moment: in a system where Return == '\n', the first condition will be false, but the latter will be true; since it's a logical OR, the while condition will always pass. In other words, you have two mutually exclusive conditions (in the case of a Return) with a logical OR; this will always evaluate to true (again, in the case of a Return key press). – Eron Sep 23 '19 at 16:30
  • this should help to understand: https://stackoverflow.com/questions/2168603/demorgan-rules-explained – 463035818_is_not_an_ai Sep 23 '19 at 16:36
  • 2
    I usually use the simple: `std::cout << "Paused. Press ENTER to continue.\n"; std::cin.ignore(1000000, '\n');` – Thomas Matthews Sep 23 '19 at 16:42
  • @tadman thank you! I already fixed it – Andre Machado do Monte Sep 23 '19 at 16:55
  • @AndreMonte Be aware that substantially modifying the code in the question can invalidate existing comments and answers. Not a big issue *this time*, so it's OK to leave it, just keep that in mind in the future... – Aconcagua Sep 23 '19 at 17:05

3 Answers3

6

At very first: enter != '\n' || enter != '\r' is a tautology: Even if enter does equal one of the characters it cannot be equal to the other one. So one of the tests must be true... You actually want to stay in the loop when enter is unequal to both values.

std::cin >> ... won't read data before you press enter, but it will discard the newlines (actually, all whitespace). So it would suffice just to read one single character right without loop (the loop again would get an endless one); solely: If the user doesn't enter anything at all before pressing 'enter' key, there's no character to read from std::cin and we'd still be waiting.

What you can do is reading entire lines:

std::string s;
std::getline(std::cin, s);

That will accept empty lines as well, so does exactly what you want (note: no loop around!).

Edit (stolen from the comments; thanks, Thomas Matthews): An even more elegant way is

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

as it won't create any additional resources that would be discarded afterwards anyway (the std::string object!).

Edit 2:

Depending on type of last input operation, there might still be a newline (or even further data) buffered, e. g. after int n; std::cin >> n;. In this case, you need to skip the input yet buffered. So you would need ignore twice.

However, if the last input operation consumed the newline already (e. g. std::getline – or if there wasn't any preceding input operation at all), then this would lead to user having to press enter twice. So you need to detect what's has been going on before.

std::cin.rdbuf().in_avail() allows you to detect how many characters are yet buffered. So you can have:

if(std::cin.rdbuf().in_avail())
{
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
std::cout << "press enter" << std::endl;
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

On some systems (including mine), though, in_avail can return 0 even though a newline is yet buffered! std::cin.sync_with_stdio(false); can fix the issue; you should execute it before very first input operation. Hopefully, you don't use C++ (streams) and C (scanf, printf, etc) IO intermixed then...

Aconcagua
  • 24,880
  • 4
  • 34
  • 59
  • But I believe that using the code as you mentioned will make able to the user to press any key to continue... I would like to only continue the program if enter key it is pressed. – Andre Machado do Monte Sep 23 '19 at 16:51
  • 1
    Nope. User can enter *anything* before pressing 'enter' key, but `std::getline` won't return until the latter occurs (how would it determine a line to be complete otherwise???). Actually, implementing a `Press ANY key to continue.` is much more complicated, relying on OS specific resources. – Aconcagua Sep 23 '19 at 16:55
  • If I use: cin.ignore... or getline.. the program does not wait to get an input... Any idea why? – Andre Machado do Monte Sep 23 '19 at 17:19
  • Have you pressed 'enter' before? Do you use your programme from within an IDE? Sometimes, IDE console can behave differently. – Aconcagua Sep 23 '19 at 17:25
  • I am using Code Runner, I tried using terminal and the results are the same... The program keeps going even whitout I have pressed any key on cin.ingnore or getline functions... – Andre Machado do Monte Sep 23 '19 at 17:35
  • That's strange. Any you don't have any code around that might prevent the piece above from getting reached at all? Have you tried in debugger? – Aconcagua Sep 23 '19 at 17:39
  • Yes I have tried debug, but it simples ignore my cin... This have never happened before.. – Andre Machado do Monte Sep 23 '19 at 17:42
  • You mean, you just step over the `getline`??? Could you have driven `std::cin` into error state? Try `std::cout << std::cin.good() << std::endl;` – if you get `0` as output you need to clear errors (`std::cin.clear()`), and you best ignore any input that might yet be buffered, otherwise previously typed 'enter' likely will lead to skipping current wait again. – Aconcagua Sep 23 '19 at 17:47
  • So code might look like: `if(!std::cin) { std::cin.clear(); std::cin.ignore(max); } std::cout << "press enter"; std::cin.ignore(max, '\n');` (note that first call to `ignore` uses default for second argument). – Aconcagua Sep 23 '19 at 17:50
  • I am getting **1** and as soon as the program enter the function I am doing cin.clear() to clear the buffer. – Andre Machado do Monte Sep 23 '19 at 17:50
  • Are you sure there's no user input buffered any more? Assume we have `int n; std::cin >> n;` and user input was `10 12`, then after reading `10`, `12` would still be in the stream and provoke waiting to fail. – Aconcagua Sep 23 '19 at 17:54
  • Try `std::cin.ignore(std::numeric_limits::max()); std::cout << "press enter"; std::cin.ignore(std::numeric_limits::max(), '\n');` – Aconcagua Sep 23 '19 at 17:56
  • 1
    Just to be sure: make an entirely new programme, just having a bare `int main(void) { std::cin.ignore(std::numeric_limits::max(), '\n'); return 0; }` – if it doesn't fail, problem is elsewhere, if it *does* – then I'm at an end for now... – Aconcagua Sep 23 '19 at 18:00
  • Using this code you provided above, It is asking for input endless... it is looping the std::cin.ignore(std::numeric_limits::max()); – Andre Machado do Monte Sep 23 '19 at 18:03
0

The easiest way to do this is with getline().

cin >> ignores whitespace, newline characters included. getline() will read an entire line, newline character included. However, it does not copy the newline character to the output string. If the user simply hit the enter key and nothing else, you'd end up with an empty string.

So, to get your desired behavior, you would construct your loop like this:

string line;
while(true)
{
    cout << "(Press Enter to Continue...) " << endl;
    getline(cin, line);

    if(line == "")
        break;
}
bindsniper001
  • 164
  • 2
  • 13
  • Using this code my program just ignores the getline(). – Andre Machado do Monte Sep 23 '19 at 18:07
  • Ignores it how? It's not possible for it to simply skip that function call. What, exactly, is it doing? – bindsniper001 Sep 23 '19 at 18:10
  • Create a sample program. Use this code as the body of the `main()` function and test it again. There is no reason that this code, by itself, shouldn't work. There's something else going on. When is `pause()` being called? Under what conditions? – bindsniper001 Sep 23 '19 at 18:14
  • When I am debuging I goes to the getline function but just passes, looks like getline it is getting something from the buffer, but even using cin.clear() it does not change the results... – Andre Machado do Monte Sep 23 '19 at 18:14
  • That's not really what's happening. The debugger isn't skipping it, but getline() in essence functions as a pause function on its own. when it is called, it halts execution until the user hits the enter key. Then it returns all the characters typed in, up to the newline. When you set a breakpoint on that function call, the breakpoint won't necessarily trigger until getline() returns. – bindsniper001 Sep 23 '19 at 18:24
  • If I create another program it works just fine... But on my program does not... I have look everything and can only be garbage on my buffer – Andre Machado do Monte Sep 23 '19 at 18:25
  • There's another issue somewhere else in your code. This loop is self-contained and shouldn't be affected by anything on the `cin` buffer. – bindsniper001 Sep 23 '19 at 18:28
  • Yes... Probably there is something else in my code that I cannot see... Do you mind taking a look? Can I send to your email, skype? Probably something small Thank you @bindsniper001 – Andre Machado do Monte Sep 23 '19 at 18:31
  • While I don't mind taking a look, I'd rather not post that information publicly. It's a good way of getting spam on my end. Unfortunately, there's also not an easy way (that I'm aware of) of sending private messages on StackOverflow. There are chat rooms, but I don't think your reputation is high enough to join one if I create it manually. It is possible to have comment discussions moved to a chat room, but I don't know what the criteria is for that to happen. – bindsniper001 Sep 23 '19 at 18:39
  • No problem! Thank you very much for your help! – Andre Machado do Monte Sep 23 '19 at 18:41
0

@Aconcagua has answered your question but this is what I want to add in.

Normally, for handling some specific kind of event in computer, we usually follow event-driven paradigm or event-callback. The idea is there is an event loop that waits for a new event coming into the system. This case, keyboard is an event, the event loop then calls event-callback. What event-callback does is it compares the value of input with some conditions then do some other tasks (it might change some state of the program or notify users).

The idea is keep CPU busy by either 2 ways.

  1. event-driven : do other tasks while waiting for a new event
  2. multithreading: multiple threads in the system. This approach has the disadvantage is at data-race

Have fun

khanh
  • 600
  • 5
  • 20