Как я могу запретить scanf () вечно ждать ввода символа?

c scanf

14816 просмотра

5 ответа

71 Репутация автора

Я хочу выполнить следующие вещи в консольном приложении:

  1. Если пользователь вводит символ, приложение выполнит соответствующую задачу. Например, если пользовательский ввод 1, программа выполнит задачу 1, если пользовательский ввод q, программа выйдет;
  2. Если пользователь ничего не вводит, программа будет выполнять задание по умолчанию каждые 10 секунд (время не должно быть очень строгим).

Вот мой код:

#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()это была очевидная ошибка.

Автор: user3208536 Источник Размещён: 17.01.2014 11:38

Ответы (5)


3 плюса

88808 Репутация автора

Но проблема в том, что программа будет ловить строку функции scanf () вечно, ожидая ввода символа,

Снять точку с запятой после while.

Автор: haccks Размещён: 17.01.2014 11:43

11 плюса

1864 Репутация автора

Попробуйте использовать функцию 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 () просто не слишком мой друг, но это личное дело вкуса).

Автор: Ronald Размещён: 17.01.2014 11:46

2 плюса

1103 Репутация автора

Попробуйте будильник (3)

#include <stdio.h>
#include <unistd.h>
int main(void)
{
   char buf [10];
   alarm(3);
   scanf("%s", buf);
   return 0;
}
Автор: lbaby Размещён: 17.01.2014 11:48

2 плюса

576 Репутация автора

Как уже говорили другие, лучший способ сделать действительно асинхронный ввод-вывод с select(...).

Но быстрый и грязный способ сделать то, что вы хотите, - getline(...)это возвращать количество прочитанных байтов каждый раз (не зависая при вводе-выводе) и возвращать -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);
Автор: mellowfish Размещён: 17.01.2014 11:49

9 плюса

2489 Репутация автора

Вот рабочий пример того, как это сделать 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и указывается в миллисекундах - этот пример будет ждать 2 секунды для ввода в stdin. Windows имеет WSAPoll, которая должна работать аналогично.

Автор: Graeme Размещён: 18.01.2014 12:19
Вопросы из категории :
32x32