Использование scanf в цикле while - PullRequest
12 голосов
/ 04 июня 2010

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

Я читаю "C Primer Plus" Пратты, и он продолжает использовать пример

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

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

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

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

Ответы [ 5 ]

26 голосов
/ 04 июня 2010

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

10 голосов
/ 04 июня 2010

Поскольку 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 в конце файла или неотрицательное целое число, подсчитывающее количество успешно установленных переменных.

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

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

3 голосов
/ 04 июня 2010

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

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

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

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

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

1 голос
/ 05 июня 2010

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

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

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

1 голос
/ 04 июня 2010

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

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

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

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

...