如何防止scanf()永远等待输入字符?

时间:2014-01-17 23:38:43

标签: c scanf

我想在控制台应用程序中完成以下事项:

  1. 如果用户输入了一个字符,那么应用程序就会执行该操作 相应的任务。例如,如果用户输入1,则为该程序 将执行任务1,如果用户输入q,程序将退出;
  2. 如果用户没有输入任何内容,程序将每10秒执行一次默认任务(时间不必非常严格)。
  3. 这是我的代码:

    #include <stdio.h>
    #include <time.h>
    
    char buff[64];
    char command;
    
    while(command != 'q')
    {
       begin:
       printf(">> ");
       scanf("%s", buff);
       command = buff[0];
    
       switch (command)
       {
           case '1':
           // task 1 code will be added here;
              break;
           case '2':
           // task 2 code will be added here;
              break;
           case 'q':
              printf("quit the loop.\n");
              break;
       }
    
       // wait for 10 seconds;
       Sleep(10000);
       // default task code will be added here;
    
      if(command != 'q')
      {
         goto begin;
      }
    
    }
    

    但问题是,如果没有输入字符,程序将永远陷入scanf()函数的行,等待输入字符。所以我想知道如何在一段时间之后跳过scanf()的行,我的意思是,例如,如果1秒后没有输入,程序可以继续,以便完成上面列出的第二件事。

    平台是Windows,如果重要的话。

    我在while()明显错误后删除了分号。

5 个答案:

答案 0 :(得分:11)

尝试使用select()函数。然后你可以等待10秒,直到你可以不受阻塞地读取标准输入。如果select()返回零,则执行默认操作。 我不知道这是否适用于Windows,它是POSIX标准。如果你碰巧在unix / linux上开发,请尝试man select

我刚用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;
}

注意:下面的poll()示例也可以,没问题。其余的我选择将可用字节读入缓冲区(最多MAXBYTES)。之后可以进行扫描。 (scanf()对我的朋友来说并不是太多,但那是个人品味问题。)

答案 1 :(得分:9)

以下是如何使用poll执行此操作的示例(可能是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;
}

超时是poll的第三个参数,以毫秒为单位 - 此示例将在stdin上等待2秒。 Windows有WSAPoll,它的工作方式应该相同。

答案 2 :(得分:3)

  

但问题是程序会永远陷入scanf()函数行等待输入字符,

while之后删除分号。

答案 3 :(得分:2)

尝试闹铃(3)

#include <stdio.h>
#include <unistd.h>
int main(void)
{
   char buf [10];
   alarm(3);
   scanf("%s", buf);
   return 0;
}

答案 4 :(得分:2)

正如其他人所说,真正实现异步IO的最佳方法是使用select(...)

但是快速而肮脏的方式来做你想要的是getline(...),它将返回每次读取的字节数(不挂在IO上),并且在没有读取字节时返回-1。

以下内容来自getline(3)手册页:

// 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);