Почему является scanf () порождением бесконечного цикла в этом коде?

Я делаю поспешные выводы, но я предполагаю, что вы хотите получить полную дату, а не только «10» дня?

gawk -F'|' '{print gensub( /^(.{8}).*/, "\\1", "1",$5)}' data 
20190110
20190110
20190110
20190110
45
задан Abhi 29 May 2018 в 13:19
поделиться

7 ответов

Решение: необходимо добавить fflush(stdin);, когда 0 возвращается от scanf.

Причина: Это, кажется, оставляет входной символ в буфере, когда с ошибкой встречаются, таким образом, каждый раз scanf называют им, просто продолжает пытаться обработать недопустимый символ, но никогда не удалять его формируют буфер. Когда Вы будете звонить fflush, входной буфер (stdin) будет очищен так, недопустимый символ больше не будет обрабатываться повторяемо.

Вы Программируете Измененный: Ниже Ваша программа, измененная с необходимым изменением.

#include <stdio.h>

int main()
{
    int number, p = 0, n = 0;

    while (1) {
        printf("-> ");
        if (scanf("%d", &number) == 0) {
            fflush(stdin);
            printf("Err...\n");
            continue;
        }

        if (number > 0) p++;
        else if (number < 0) n++;
        else break; /* 0 given */
    }

    printf("Read %d positive and %d negative numbers\n", p, n);
    return 0;
}
1
ответ дан 26 November 2019 в 21:25
поделиться

scanf использует только ввод, который соответствует строке формата, возвращая количество использованных символов. Любой символ, который не соответствует строке формата, вызывает остановку сканирования и оставляет недопустимый символ в буфере. Как говорили другие, вам все равно нужно очистить недопустимый символ из буфера, прежде чем продолжить. Это довольно грязное исправление, но оно удалит неправильные символы из вывода.

char c = '0';
if (scanf("%d", &number) == 0) {
  printf("Err. . .\n");
  do {
    c = getchar();
  }
  while (!isdigit(c));
  ungetc(c, stdin);
  //consume non-numeric chars from buffer
}

edit: исправлен код, чтобы удалить все нечисловые символы за один раз. Больше не будет выводить несколько ошибок "Errs" для каждого нечислового символа.

Здесь довольно хороший обзор scanf.

36
ответ дан 26 November 2019 в 21:25
поделиться

Вместо того, чтобы использовать scanf () и иметь дело с буфером, имеющим недопустимый символ, используйте fgets () и sscanf () .

/* ... */
    printf("0 to quit -> ");
    fflush(stdout);
    while (fgets(buf, sizeof buf, stdin)) {
      if (sscanf(buf, "%d", &number) != 1) {
        fprintf(stderr, "Err...\n");
      } else {
        work(number);
      }
      printf("0 to quit -> ");
      fflush(stdout);
    }
/* ... */
3
ответ дан 26 November 2019 в 21:25
поделиться

Очистите входной буфер перед сканированием:

while(getchar() != EOF) continue;
if (scanf("%d", &number) == 0) {
    ...

Я собирался предложить fflush (stdin) , но, по-видимому, это приводит к неопределенному поведению .

В ответ на ваш комментарий, если вы хотите, чтобы появилось приглашение, вы должны сбросить выходной буфер. По умолчанию это происходит только при печати новой строки. Например:

while (1) {
    printf("-> ");
    fflush(stdout);
    while(getchar() != EOF) continue;
    if (scanf("%d", &number) == 0) {
    ...
-1
ответ дан 26 November 2019 в 21:25
поделиться

Из-за проблем с scanf , указанных в других ответах, вам действительно стоит подумать об использовании другого подхода. Я всегда считал scanf слишком ограниченным для серьезного чтения и обработки ввода. Лучше просто читать целые строки с помощью fgets , а затем работать с ними с помощью таких функций, как strtok и strtol (которые, кстати, будут правильно анализировать целые числа и сообщать вы именно там, где начинаются недопустимые символы).

3
ответ дан 26 November 2019 в 21:25
поделиться

scanf () оставляет « a » во входном буфере для следующего раза. Вероятно, вам следует использовать getline () , чтобы прочитать строку независимо от того, что она делает, а затем проанализировать ее с помощью strtol () или подобного.

(Да, getline () относится к GNU, а не к POSIX. И что? Вопрос помечен как «gcc» и «linux».

6
ответ дан 26 November 2019 в 21:25
поделиться

Я думаю, вам просто нужно очистить буфер, прежде чем продолжить цикл. Что-то вроде этого, вероятно, сработает, хотя я не могу проверить то, что пишу отсюда:

int c;
while((c = getchar()) != '\n' && c != EOF);
7
ответ дан 26 November 2019 в 21:25
поделиться
Другие вопросы по тегам:

Похожие вопросы: