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