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

Управляющие операторы С: циклы 201
В программе из листинга 6.1 применяется тип long, что позволяет вводить большие числа. Для согласованности переменная sum инициализируется значением 0L (ноль типа long), а не 0 (ноль типа int), хотя автоматическое преобразование типов в С позволяет указывать просто 0.
Ниже показан пример выполнения этой программы:
Введите целое число для последующего суммирования (или q для завершения
программы): 44
Введите следующее целое число (или q для завершения программы): 33
Введите следующее целое число (или q для завершения программы): ее
Введите следующее целое число (или q для завершения программы): 121
Введите следующее целое число (или q для завершения программы): q
Сумма введенных целых чисел равна 286.
Комментарии к программе
Для начала взглянем на цикл while. Условием проверки этого цикла является следующее выражение:
status == 1
В языке С символы == представляют операцию равенства, т.е. это выражение проверяет, равно ли значение переменной status числу 1. Не путайте его с выражением status = 1, которое присваивает переменной status значение 1. Благодаря условию проверки status == 1, цикл повторяется до тех пор, пока переменная status имеет значение 1. На каждой итерации в цикле текущее значение num добавляется к значению переменной sum, так что sum хранит промежуточную сумму. Когда переменная status получит значение, отличное от 1, цикл завершается, и программа выводит финальное значение sum.
Чтобы программа работала корректно, на каждой итерации цикла она должна получать новое значение для переменной num и переустанавливать переменную status. Это достигается за счет использования двух свойств функции scanf(). Во-первых, функция scanf() вызывается с целью чтения нового значения для num. Во-вторых, возвращаемое значение scanf() применяется для выяснения, была ли попытка чтения успешной. Как отмечалось в главе 4, функция scanf() возвращает количество успешно прочитанных элементов. Если scanf() успешно считывает целое число, она помещает его в переменную num и возвращает значение 1, которое присваивается переменной status. (Обратите внимание, что входное значение попадает в num, а не в status.) В результате обновляются значения num и status, после чего цикл while переходит на следующую итерацию. Если вы введете нечисловое значение, такое как q, то функция scanf() не обнаружит целого числа при вводе и возвратит значение 0, которое затем получит переменная status. Входной символ q из-за того, что он не является числом, возвращается во входную очередь; он вообще не считывается. (В действительности цикл завершается по причине ввода любого нечислового значения, а не только q, но предложение ввести q является более простой инструкцией для пользователя, чем сообщение о вводе любого нечислового значения.)
Если перед попыткой преобразовать значение функция scanf() сталкивается с проблемой (например, возникает конец файла или сбой оборудования), она возвращает специальное значение EOF (end of file — конец файла), которое обычно определено как -1. Это значение также приводит к прекращению цикла.
Такое двойное использование функции scanf() позволяет избежать трудноразрешимого аспекта интерактивного ввода в цикле: каким образом сообщить циклу о том, когда он должен прекратиться? Предположим, например, что scanf() не имеет
202 Глава 6 возвращаемого значения. Тогда единственное, что изменяется на каждой итерации — это значение переменной num. Значение num можно было бы задействовать при определении момента завершения цикла, скажем, указав num > 0 (num больше 0) или num ! = 0 (num не равно 0) в условии проверки, но это воспрепятствовало бы вводу определенных значений, таких как -3 или 0. Взамен можно было бы добавить в цикл дополнительный код, например, выдающий на каждой итерации запрос “Намерены ли вы продолжать? <���да/нет>”, после чего проверять, ввел ли пользователь утвердительный ответ. Однако такой подход выглядит несколько громоздким и замедляет ввод. Применение возвращаемого значения scanf() позволяет избежать этих проблем.
Читать дальше