0

I'm doing a counter where I'm showing how many seconds the user has to make the input. The problem is that when I use scanf(), the program will stop and will wait for the answer, but I don't want that. I'd like to keep running the counter even thought the user doesn't put anything.

Example:

for(int i=10;i>=0;i--){
            i==0? printf("time over\n"):printf("%d seconds left\n",i);
            scanf("%s", decision);
            sleep(1);
        }

What can i do to solve this?

  • 4
    you have to use threads to implement that – mangusta Sep 28 '19 at 02:36
  • 2
    What OS are you using? – user3386109 Sep 28 '19 at 02:38
  • @mangusta On Linux, you can do non-blocking IO on `stdin`: https://stackoverflow.com/questions/717572/how-do-you-do-non-blocking-console-i-o-on-linux-in-c – Dai Sep 28 '19 at 02:45
  • This won't be easy. Using threads is one way, although not the only way. You could also look into doing immediate, nonblocking, character-at-a-time input. (This would *not* involve `scanf`!) – Steve Summit Sep 28 '19 at 03:28
  • 2
    Using `select, pselect, poll or epoll` and then polling a set of file descriptors with a timeout set is one way, manually using signal handlers is another. `scanf` doesn't even enter the running. – David C. Rankin Sep 28 '19 at 03:31
  • Under a Unix-like OS, you could (1) put the terminal in 'cbreak' mode, (2) print the remaining time, (3) poll the input for one character if available, (4) display (echo) the character if you got one, (5) sleep for a second or so, and (6) loop back to (2). It would be a fun little program to write. You cold probably use [ncurses](https://en.wikipedia.org/wiki/Ncurses) to good effect. – Steve Summit Sep 28 '19 at 03:40
  • Style comment: don't use a ternary operator when an `if` / `else` is more appropriate, which is definitely the case with the first line in the body of the loop. Use the ternary operator when you assign its result, or perhaps if you test its result (and I mean the result of the overall operator, not the result of the condition which is always tested, of course). – Jonathan Leffler Sep 28 '19 at 05:52
  • related: https://stackoverflow.com/questions/9208296/ncurses-keyboard-input – pmg Sep 28 '19 at 10:58

1 Answers1

2

Like mentioned in the comments one possibility would be to use poll.

man poll says:

poll() examines a set of file descriptors to see if some of them are ready for I/O or if certain events have occurred on them.

In code it could look like this:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/poll.h>
#include <stdbool.h>

int main() {
    struct pollfd fds[1];
    fds[0].fd = STDIN_FILENO;
    fds[0].events = POLLIN;

    bool dataAvailable = false;
    for (int i = 10; i >= 0 && !dataAvailable; i--) {
        switch (poll(fds, 1, 1000)) {
            case -1:
                perror("poll failed");
                exit(1);
            case 0:
                printf("%d seconds left\n", i);
                break;
            default:
                dataAvailable = true;
        }
    }

    if (dataAvailable) {
        //read from stdin
    } else {
        fprintf(stderr, "no input\n");
        exit(1);
    }

    return 0;
}
Stephan Schlecht
  • 26,556
  • 1
  • 33
  • 47
  • That's awesome, but only one thing more that i'd like to do. When scanf is invoke, the message of the seconds that appears after, move the cursor of the console and it doesn't let me see the whole string that i want to put. how can i solve this? example : `10 seconds left my str9 seconds left ing is 8 seconds left thi7 seconds left s` – Kleiver Marcano Sep 30 '19 at 00:46
  • I'd use ncurses for a purpose like that. It would allow you to define text-based UI where you show countdown at a specific screen location in the terminal and the entry of the data in another one. – Stephan Schlecht Oct 02 '19 at 15:06