Вопрос:

Scanf не удается, почему?

c scanf

6041 просмотра

4 ответа

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


когда я написал это, скомпилируйте и запустите:

int x;   
scanf ("%d", &x);  
while (x!=4) {  
    scanf ("%d", &x);  
}

и, вставляя символ или двойное число меньше 4, он входит в бесконечный цикл.
при вставке double больше 4 он заканчивается.
Любое объяснение?

Автор: Aboelnour Источник Размещён: 25.10.2010 03:24

Ответы (4)


-3 плюса

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

% D, который вы передали scanf, говорит ему проанализировать int. Когда вы вводите double, он не может ни проанализировать, ни сохранить проанализированные данные в переменной x, потому что double использует 64 бита на 32-битных компьютерах и int только 32-битные, что вызывает сегментацию. Ошибка или случайные побочные эффекты.

Автор: Vinícius Gobbo A. de Oliveira Размещён: 25.10.2010 03:29

6 плюса

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

Вы не проверяете, scanfдействительно ли это удалось, поэтому вы застряли на ошибке. С каждым циклом, scanfпопытка чтения и сбой.

scanf возвращает количество успешно прочитанных элементов, поэтому измените цикл на что-то вроде этого while (x!=4) { if (scanf("%d",&x) != 1) break; }

Автор: Let_Me_Be Размещён: 25.10.2010 03:30

5 плюса

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

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

вход: 42 23 фу ...
scanf: ^
х 42
scanf: ^
х 23
scanf: ^
х непригодный
scanf: ^
х непригодный
scanf: ^
х непригодный
scanf: ^
х непригодный
scanf: ^
х непригодный
Автор: pmg Размещён: 25.10.2010 03:34

11 плюса

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

Решение

Из стандарта языка C (n1256) :

7.19.6.2 Функция fscanf
...
4 Функция fscanf выполняет каждую директиву формата по очереди. В случае сбоя директивы, как описано ниже, функция возвращается. Сбои описываются как сбои ввода (из-за возникновения ошибки кодирования или недоступности вводимых символов) или сбоев сопоставления (из-за неправильного ввода).
...
7 Директива, которая является спецификацией преобразования, определяет набор соответствующих входных последовательностей, как описано ниже для каждого спецификатора. Спецификация преобразования выполняется в следующие шаги:

8 Входные пробельные символы (как указано в функции isspace) пропускаются, если в спецификации не указан спецификатор [ , c или n . 250)

9 Элемент ввода считывается из потока, если спецификация не содержит спецификатор n . Элемент ввода определяется как самая длинная последовательность символов ввода, которая не превышает заданную ширину поля и которая является или является префиксом соответствующей последовательности ввода. 251) Первый символ, если он есть, после элемента ввода остается непрочитанным. Если длина входного элемента равна нулю, выполнение директивы заканчивается неудачей; это условие является ошибкой сопоставления, если только конец файла, ошибка кодирования или ошибка чтения не предотвратили ввод из потока, и в этом случае это сбой ввода.

10 За исключением случая с указателем % , элемент ввода (или, в случае % nдиректива (количество вводимых символов) преобразуется в тип, соответствующий спецификатору преобразования. Если элемент ввода не совпадает с последовательностью, выполнение директивы завершается неудачно: это условие является ошибкой совпадения. Если подавление присваивания не было указано *, результат преобразования помещается в объект, на который указывает первый аргумент после аргумента формата, который еще не получил результат преобразования. Если этот объект не имеет подходящего типа или если результат преобразования не может быть представлен в объекте, поведение не определено.

Акцент добавлен в пункте 10. Спецификатор %dпреобразования ожидает, что входной текст будет отформатирован как десятичное целое число. Если это не так, преобразование завершается неудачно, и символ, вызвавший сбой преобразования, остается во входном потоке. Дальнейшие вызовы scanf()со %dспецификатором преобразования будут подавлены тем же символом.

scanf()возвращает количество успешных заданий; вам нужно проверить этот результат, чтобы убедиться, что преобразование прошло успешно, например:

int x = 0;
while (x != 4)
{
  int result = scanf("%d", &x);
  if (result != 1)
  {
    printf("Last call to scanf() failed; exiting\n");
    break;
  }
}

К сожалению, у вас все еще плохой ввод в потоке ввода. Существует ряд стратегий для борьбы с этим. Вы можете удалить оскорбительный символ с помощью getcharи повторить попытку:

while (x != 4)
{
  int tmp;
  if (scanf("%d", &tmp) == 0)
    getchar();
  else
    x = tmp;
}

Или вы можете попытаться прочитать до следующего символа новой строки, предполагая, что весь оставшийся ввод b0rked:

while (x != 4)
{
  int tmp;
  if (scanf("%d", &tmp) == 0)
    while (getchar() != '\n')
      ;
  else
    x = tmp;
}

Или вы можете попытаться прочитать входные данные как текст и конвертировать в целое число, используя strtol()(моя предпочтительная техника):

char input[SOME_SIZE];
int x = 0;
...
while (x != 4)
{
  if (fgets(input, sizeof input, stdin))
  {
    char *check;
    int tmp = (int) strtol(input, &check, 10);
    if (!isspace(*check) && *check != 0)
    {
      printf("%s is not a valid integer: try again\n", input);
    }
    else
    {
      x = tmp;
    }
  }
  else
  {
    printf("Read error on standard input\n");
    break;
  }
}

Это больше работы, но она позволяет вам отловить неверные данные, прежде чем они будут назначены x.

Автор: John Bode Размещён: 25.10.2010 04:27
Вопросы из категории :
32x32