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

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

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

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

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

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

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

5 ответов


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


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

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

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

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

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

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

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

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


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

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

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

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

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


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

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

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

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


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

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

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