How can I prevent scanf() to wait forever for an input character?

前端 未结 5 2124
悲哀的现实
悲哀的现实 2020-12-01 16:56

I want to fulfill the following things in a console application:

  1. If user inputs a character, the application will do the corresponding task. For example, if us
相关标签:
5条回答
  • 2020-12-01 17:00

    But the problem is the program will trap at the line of scanf() function forever to wait for an input character,

    Remove the semicolon after while.

    0 讨论(0)
  • 2020-12-01 17:06

    Try using the select() function. Then you can wait for 10 seconds until you can read from stdin without blocking. If select() returns with zero, perform the default action. I don't know if this works on windows, it's POSIX standard. If you happen to develop on unix/linux, try man select

    I just wrote a working example using select:

    #include <stdlib.h>
    #include <stdio.h>
    #include <sys/select.h>
    #include <sys/time.h>
    #include <sys/types.h>
    #include <unistd.h>
    #include <string.h>
    #include <errno.h>
    
    #define MAXBYTES 80
    
    int main(int argc, char *argv[])
    {
            fd_set readfds;
            int    num_readable;
            struct timeval tv;
            int    num_bytes;
            char   buf[MAXBYTES];
            int    fd_stdin;
    
            fd_stdin = fileno(stdin);
    
            while(1) {
                    FD_ZERO(&readfds);
                    FD_SET(fileno(stdin), &readfds);
    
                    tv.tv_sec = 10;
                    tv.tv_usec = 0;
    
                    printf("Enter command: ");
                    fflush(stdout);
                    num_readable = select(fd_stdin + 1, &readfds, NULL, NULL, &tv);
                    if (num_readable == -1) {
                            fprintf(stderr, "\nError in select : %s\n", strerror(errno));
                            exit(1);
                    }
                    if (num_readable == 0) {
                            printf("\nPerforming default action after 10 seconds\n");
                            break;  /* since I don't want to test forever */
                    } else {
                            num_bytes = read(fd_stdin, buf, MAXBYTES);
                            if (num_bytes < 0) {
                                    fprintf(stderr, "\nError on read : %s\n", strerror(errno));
                                    exit(1);
                            }
                            /* process command, maybe by sscanf */
                            printf("\nRead %d bytes\n", num_bytes);
                            break; /* to terminate loop, since I don't process anything */
                    }
            }
    
            return 0;
    }
    

    Note: the poll() example below is OK too, no problem. For the rest I chose to read the available bytes into a buffer (up to MAXBYTES). It can be (s)scanned afterwards. (scanf() just isn't too much my friend, but that's a personal taste matter).

    0 讨论(0)
  • 2020-12-01 17:08

    As others have said, the best way to do truly async IO is with select(...).

    But a quick and dirty way to do what you want is with getline(...) which will return the number of bytes read every time (not hanging on IO) and returns -1 on no bytes read.

    The following is from the getline(3) man page:

    // The following code fragment reads lines from a file and writes them to standard output.  
    // The fwrite() function is used in case the line contains embedded NUL characters.
    
    char *line = NULL;
    size_t linecap = 0;
    ssize_t linelen;
    while ((linelen = getline(&line, &linecap, fp)) > 0)
        fwrite(line, linelen, 1, stdout);
    
    0 讨论(0)
  • 2020-12-01 17:11

    Try alarm(3)

    #include <stdio.h>
    #include <unistd.h>
    int main(void)
    {
       char buf [10];
       alarm(3);
       scanf("%s", buf);
       return 0;
    }
    
    0 讨论(0)
  • 2020-12-01 17:14

    Here is a working example of how to do this with poll (probably the most 'correct' way on Linux):

    #include <unistd.h>
    #include <poll.h>
    #include <stdio.h>
    
    int main()
    {
        struct pollfd mypoll = { STDIN_FILENO, POLLIN|POLLPRI };
        char string[10];
    
        if( poll(&mypoll, 1, 2000) )
        {
            scanf("%9s", string);
            printf("Read string - %s\n", string);
        }
        else
        {
            puts("Read nothing");
        }
    
        return 0;
    }
    

    The timeout is the third argument to poll and is in milliseconds - this example will wait for 2 seconds for input on stdin. Windows has WSAPoll, which should work similarly.

    0 讨论(0)
提交回复
热议问题