Вероятно, чрезвычайно простой ответ на этот чрезвычайно простой вопрос:
Я читаю "C Краткую информацию Плюс" Pratta, и он продолжает использовать пример
while (scanf("%d", &num) == 1)...
== 1 действительно необходимое? Кажется, что можно было просто записать:
while (scanf("%d", &num))
Кажется, что тест равенства является ненужным, так как scanf возвращает количество чтения объектов, и 1 сделал бы цикл с условием продолжения верным. Причина состоит в том, чтобы удостовериться, что чтение числа элементов равняется точно 1, или действительно ли это является полностью лишним?
В C 0 оценивается как false, а все остальное - как true. Таким образом, если scanf вернет EOF, что является отрицательным значением, то цикл будет оценивать true, а это не то, что вам нужно.
Вы правильно поняли код C.
Иногда причина для проверки количества прочитанных элементов состоит в том, что кто-то хочет убедиться, что все элементы были прочитаны, вместо того, чтобы scanf преждевременно завершил работу, когда входные данные не соответствуют ожидаемому типу. В данном конкретном случае это не имело значения.
Обычно scanf - плохой выбор функций, потому что он не отвечает потребностям интерактивного ввода от человека-пользователя. Обычно комбинация fgets и sscanf дает лучшие результаты. В данном конкретном случае это не имело значения.
Если в последующих главах объясняется, почему некоторые методы кодирования лучше, чем этот тривиальный пример, - хорошо. Но если нет, вам следует выбросить книгу, которую вы читаете.
С другой стороны, ваш заменяющий код - это не совсем замена. Если scanf возвращает -1, тогда ваш цикл while будет выполнен.
Поскольку 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
может быть достаточно для некоторого простого синтаксического анализа, но даже в этом случае он легко переполнен крайними случаями и ошибками.
Его, вероятно, можно было бы написать без явного сравнения (см. Ответ JRL), но зачем? Я бы сказал, что условия без сравнения следует использовать только со значениями, которые имеют явно логическую семантику (например, вызов isdigit ()
). Все остальное должно использовать явное сравнение. В этом случае (результат scanf
) семантика явно не логическая, поэтому явное сравнение в порядке.
Кроме того, сравнение, которое обычно можно опустить, обычно является сравнением с нулем . Когда вы чувствуете желание опустить сравнение с чем-то другим (например, 1
в данном случае), лучше дважды подумать и убедиться, что вы знаете, что делаете (снова см. Ответ JRL).
В любом случае, когда сравнение может быть безопасно опущено, а вы фактически опускаете его, фактическое семантическое значение условия остается тем же. Это абсолютно не влияет на эффективность результирующего кода, если вас это беспокоит.
Хотя вы правы, что это не является строго необходимым, некоторые люди предпочитают это по нескольким причинам.
Во-первых, при сравнении с 1 оно становится явным булевым значением (true или false). Без сравнения вы проверяете целое число, что допустимо в языке C, но не в более поздних языках (например, C#).
Во-вторых, некоторые люди могут прочитать вторую версию в терминах while([функция]), а не while([возвращаемое значение]), и быть на мгновение сбитыми с толку тестированием функции, когда явно имеется в виду тестирование возвращаемого значения.
Это может быть полностью вопросом личных предпочтений, и, насколько я понимаю, оба варианта являются правильными.