Используя scanf в некоторое время цикле

Вероятно, чрезвычайно простой ответ на этот чрезвычайно простой вопрос:

Я читаю "C Краткую информацию Плюс" Pratta, и он продолжает использовать пример

while (scanf("%d", &num) == 1)...

== 1 действительно необходимое? Кажется, что можно было просто записать:

while (scanf("%d", &num))

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

12
задан Nakilon 27 May 2013 в 04:25
поделиться

5 ответов

В C 0 оценивается как false, а все остальное - как true. Таким образом, если scanf вернет EOF, что является отрицательным значением, то цикл будет оценивать true, а это не то, что вам нужно.

26
ответ дан 2 December 2019 в 03:38
поделиться

Вы правильно поняли код C.

Иногда причина для проверки количества прочитанных элементов состоит в том, что кто-то хочет убедиться, что все элементы были прочитаны, вместо того, чтобы scanf преждевременно завершил работу, когда входные данные не соответствуют ожидаемому типу. В данном конкретном случае это не имело значения.

Обычно scanf - плохой выбор функций, потому что он не отвечает потребностям интерактивного ввода от человека-пользователя. Обычно комбинация fgets и sscanf дает лучшие результаты. В данном конкретном случае это не имело значения.

Если в последующих главах объясняется, почему некоторые методы кодирования лучше, чем этот тривиальный пример, - хорошо. Но если нет, вам следует выбросить книгу, которую вы читаете.

С другой стороны, ваш заменяющий код - это не совсем замена. Если scanf возвращает -1, тогда ваш цикл while будет выполнен.

3
ответ дан 2 December 2019 в 03:38
поделиться

Поскольку scanf возвращает значение EOF (равное -1) в конце файла, цикл в том виде, в котором он был записан, верен. Он выполняется до тех пор, пока ввод содержит текст, соответствующий % d , и останавливается либо при первом несовпадении, либо в конце файла.

С первого взгляда было бы яснее, если бы scanf ожидал более одного ввода ....

while (scanf("%d %d", &x, &y)==2) { ... }

выйдет из цикла, когда в первый раз не удалось сопоставить два значения, либо из-за до конца файла до конца файла ( scanf возвращает EOF (который равен -1)) или при ошибке сопоставления ввода (например,вход xyzzy 42 не соответствует % d% d , поэтому scanf останавливается при первом сбое и возвращает 0 без записи ни в x или y ), когда он возвращает какое-то значение меньше 2.

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

Редактировать: Исправлена ​​ошибка: scanf возвращает EOF в конце файла или неотрицательное целое число, считая количество успешно установленных переменных.

Ключевым моментом является то, что, поскольку любое ненулевое значение является ИСТИНА в C, неспособность правильно проверить возвращаемое значение в таком цикле может легко привести к неожиданному поведению. В частности, while (scanf (...)) представляет собой бесконечный цикл, если он не встречает входной текст, который нельзя преобразовать в соответствии с его форматом.

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

10
ответ дан 2 December 2019 в 03:38
поделиться

Его, вероятно, можно было бы написать без явного сравнения (см. Ответ JRL), но зачем? Я бы сказал, что условия без сравнения следует использовать только со значениями, которые имеют явно логическую семантику (например, вызов isdigit () ). Все остальное должно использовать явное сравнение. В этом случае (результат scanf ) семантика явно не логическая, поэтому явное сравнение в порядке.

Кроме того, сравнение, которое обычно можно опустить, обычно является сравнением с нулем . Когда вы чувствуете желание опустить сравнение с чем-то другим (например, 1 в данном случае), лучше дважды подумать и убедиться, что вы знаете, что делаете (снова см. Ответ JRL).

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

1
ответ дан 2 December 2019 в 03:38
поделиться

Хотя вы правы, что это не является строго необходимым, некоторые люди предпочитают это по нескольким причинам.

Во-первых, при сравнении с 1 оно становится явным булевым значением (true или false). Без сравнения вы проверяете целое число, что допустимо в языке C, но не в более поздних языках (например, C#).

Во-вторых, некоторые люди могут прочитать вторую версию в терминах while([функция]), а не while([возвращаемое значение]), и быть на мгновение сбитыми с толку тестированием функции, когда явно имеется в виду тестирование возвращаемого значения.

Это может быть полностью вопросом личных предпочтений, и, насколько я понимаю, оба варианта являются правильными.

1
ответ дан 2 December 2019 в 03:38
поделиться
Другие вопросы по тегам:

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