Использование scanf в цикле while

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

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

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

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

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

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

Ответ 1

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

Ответ 2

Так как 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

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

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

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

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

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

Ответ 4

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

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

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

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

Ответ 5

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

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

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