Урок 8. Другие операторы цикла

Цикл с условием (while)

Очень часто заранее невозможно сказать, сколько раз надо выполнить какую-то операцию, но можно определить условие, при котором она должна заканчиваться. Такое задание на русском языке может выглядеть так: делай эту работу до тех пор, пока она не будет закончена (пили бревно, пока оно не будет распилено; иди вперед, пока есть время). Слово пока на английском языке записывается как while, и так же называется еще один вид цикла.
Цикл while состоит из заголовка и тела цикла:

while(условие)
{
тело_цикла
}

Мы видим, что внешний вид этого цикла проще, чем цикла с параметром (for). Циклом управляет всего одно условие, которое записано в заголовке после слова while в круглых скобках.
Если условие истинно, цикл продолжает выполняться; когда условие становится неверно, цикл заканчивается.
Условие записывается в точности так же, как в условном операторе: можно использовать все операции отношения (больше, меньше и др.) и логические (И, ИЛИ, НЕ), а также арифметические. Главное, что перед выполнением тела цикла сначала проверятся условие, и если оно истинно, тело цикла выполнится, а если ложно - то нет.
Если условие неверно в самом начале, то цикл не выполняется ни разу. Поскольку условие проверяется до выполнения тела, этот цикл называется "циклом с предусловием".
Тело цикла заключается в фигурные скобки; если в теле цикла стоит всего один оператор, фигурные скобки можно опустить.

Сразу возникает вопрос: зачем столько разновидностей циклов и в каких задачах их использовать? Вернемся к примеру предыдущего урока: вывести на экран три раза приветствие. Попробуем его реализовать с помощью цикла while.
Этим циклом управляет только условие, а нам надо, чтобы цикл выполнился ровно три раза, поэтому без счетчика не обойтись. Вот только задавать значения этого параметра придется "вручную": начальное значение - до цикла, а в теле цикла - изменять параметр. Таким образом, листинг программы следующий.

#include<stdio.h>
int main()
{
int i; // параметр цикла
i=1; // начальное значение
while(i<= 3) // цикл: пока i меньше или равно 3
{
printf("Привет!\n"); // тело цикла
i++; // счетчик увеличивается
}
return 0;
}

Результат этой программы будет точно такой же, как и для цикла for из Урока 7, но код длиннее, и, очевидно, неудобней. Когда же лучше while?

Рассмотрим простой пример.
Пусть программа вводит целые положительные числа и печатает их на экране. Поскольку числа вводятся по одному, достаточно одной ячейки памяти. До каких пор будет продолжаться ввод? Давайте договоримся, что если будет введен ноль, ввод прекратится. Листинг следующий.

#include<stdio.h>
int main()
{
int N; // выделил одну ячейку
N=1; // любое ненулевое начальное N
while(N!=0) // цикл: пока N не равно 0
{
scanf("%d", &N); // чтение числа
printf("%d\n", N); // вывод на экран
}
return 0;
}

В этой программе не очень удобным моментом является то, что требуется до цикла задать начальное значение N, иначе значение этой переменной будет неопределенно ("мусор"), и нет гарантии, что в этой ячейке не ноль, и цикл даже на начнется. Другими словами, здесь более удобен цикл, в котором тело выполнятся хотя бы один раз. Такую работу сможет сделать цикл с постусловием.



Цикл с постусловием (do — while)

Цикл с постусловием проверяет условие не в начале, а в конце. Общий вид этого оператора:

do
{
тело_цикла
}
while(условие);

Видно, что прежде чем добраться до проверки условия, предварительно надо выполнить тело цикла. Этот цикл, как и предыдущий, продолжается, пока условие остается истинным. Если условие неверно с самого начала, то цикл с постусловием выполнится один раз. Наш предыдущий пример будет выглядеть красивее:

#include<stdio.h>
int main()
{
int N;
do // цикл
{
scanf("%d", &N); // чтение числа
printf("%d\n", N); // вывод на экран
}
while(N!=0); // условие: пока N не равно 0
return 0;
}

Цикл с постусловием часто применяют для обеспечения контроля ввода.
Любая программа должна обеспечивать защиту от неверного ввода данных (иногда такую защиту называют "защитой от дурака" —fool proof). Поскольку пользователь может вводить данные неверно сколько угодно раз, то надо использовать цикл с условием. С другой стороны, по крайней мере, один раз надо ввести число, поэтому предпочтительнее цикл с постусловием.
В следующем примере, допустим, для вычислений требуется натуральное число (целое положительное). В этом случае в начале программы рекомендуется вставить код, который будет обеспечивать проверку корректности введенных данных:

do
{
printf("\nВведите натуральное число: ");
scanf("%d", &N);
}
while(N<=0); // если число неположительное, цикл повторится

Резюме

Операторы while и do - while используются для организации циклов, когда числом повторений заранее неизвестно. Циклом управляет только логическое условие. Тело цикла while может ни разу не выполниться, цикл do - while выполнится по крайней мере один раз.

Вопросы для самопроверки

1. В каких случаях используется оператор цикла с условием?
2. Какие операции можно использовать в записи условия?
3. Как работает оператор цикла с постусловием?
4. В каком случае в записи тела цикла фигурные скобки можно опустить?
5. Может ли тело цикла с условием не выполниться ни разу?

 

Задания для самостоятельной работы к уроку 8

1. С помощью цикла while запишите программу табулирования функции (см. задания 6, 7, 8, 9, 10 Урока 7).
2. Записать (еще раз) программу вычисления площади треугольника по формуле Герона с проверкой существования треугольника с указанными длинами сторон (см. Указания к заданию 4 Урока 6). В случае, если треугольник не существует, предложить повторить ввод.

 

Урок 9. Интересные задачи с целыми числами

Целочисленное деление

С целочисленными и вещественными данными все операции выполняются одинаково, кроме деления. При выполнении арифметических операций действует правило: если операнды одного типа, то результат операции этого же типа. Если умножаем два целых числа - результат тоже целое число. Если делим одно вещественное число на другое, то и частное тоже вещественное число (то есть содержит целую и дробную часть).

Распространяя это правило на операцию деления целых чисел, можно прийти к заключению: если целое делим на целое, результат тоже целое. Дробная часть просто отбрасывается. Таким образом, имея описание переменных и действия:

int n,m k;
n=10;
m=4;
k=n/m;

получим, что k=2 (поскольку при "обычном" делении 10/4=2,5).

Это свойство целочисленного деления используется в разнообразных алгоритмах с целыми числами. Рассмотрим одну такую задачу:
Ввести целое число и определить, сколько в нем цифр.
Для решения этой задачи обычно применяется такой алгоритм. Число делится на 10 нацело (отбрасывается остаток), "укороченное" число заносится в эту же ячейку, и так до тех пор, пока результат деления не равен нулю. С помощью специальной переменной-счетчика считаем, сколько раз выполнялось деление - столько цифр и было в числе.
Понятно, что нельзя заранее определить, сколько раз надо разделить число, поэтому надо использовать цикл с условием. В качестве условия выступает сравнение нашего числа с нулем. Листинг следующий.

#include<stdio.h>
int main()
{
int count; // count - переменная-счетчик
int N; // исходное число
count=0; // обнуляем значение счетчика
printf("\nВведите число N\n");
scanf("%d", &N); // ввод N с клавиатуры
while( N>0 ) // делать, пока N>0
{
N = N / 10; // здесь целочисленное деление,
// результат заносится в эту же ячейку N
count++; // счетчик увеличивается на 1
printf("N=%d count=%d\n", N, count);
}
printf("В этом числе %d цифр\n", count);
}

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

printf("N=%d count=%d\n", N, count);

Пусть при выполнении было введено число 68792. Тогда протокол (порядок действий) работы программы следующий:

Введите число
68792
N=6879 count=1
N=687 count=2
N=68 count=3
N=6 count=4
N=0 count=5
В этом числе 5 цифр

Кстати, в этой программе использовали один из приемов отладки программ: промежуточную печать. Оператор printf() можно ставить в любой точке программы, где мы не совсем уверены в промежуточных результатах.

Остаток от деления

Остается открытым вопрос: окончательно ли пропадает остаток от деления. А вот и нет. Существует специальная операция, похожая на деление (в том смысле, что она тоже является операцией деления), но результат которой как раз и есть остаток от деления. Эта операция обозначается знаком процента % и применяется только для целочисленных переменных.
Например, 8 делится на 4 без остатка, а остаток от деления 9 на 4 равен 1.
Вернемся к ранее приведенному примеру, только теперь используя операцию остаток от деления:

int n,m, k;
n=10;
m=4;
k=n % m;

В результате операции получим остаток от деления k=2, т.к. 10-8=2.
Замечательное свойство остатка от деления то, что он принимает значения от 0 до m-1, где m - делитель. То есть эта операция позволяет получать целые числа в заданном диапазоне. Убедимся в этом на примерах.
Так, остаток от деления любого натурального числа на 8 даст число от 0 до 7. Остаток от деления на 2 - это будут 0 либо 1.

Операцию целочисленного деления применяют в разных целочисленных алгоритмах. Она удобна, если надо, например, из десятичного числа выделить последнюю цифру. В этом случае достаточно число нацело разделить на 10, остаток будет принадлежать диапазону от 0 до 9.
Подумайте, а как выделить из натурального числа две последние цифры? Совершенно верно, найти остаток от деления числа на 100.

С помощью совместного использования обеих операций целочисленного деления можно реализовать много алгоритмов. Попробуем, например, "растащить" трехзначное число на отдельные цифры. Алгоритм рассмотрим на примере.
Пусть наше число равно 678. Сначала, выполнив операцию 678 % 10, получим "младшую" цифру 8, сохраним ее в отдельной ячейке. Далее это же число делим нацело: 678 / 10 оставляет двузначное число 67. Повторим эти действия к двузначному числу, а для однозначного и повторять не надо, оно и так цифра.

#include<stdio.h>
int main()
{
int n1,n2,n3; // ячейки для цифр
int N; // исходное число
printf("Введите трехзначное число\n");
scanf("%d", &N); // ввод N с клавиатуры
n3=N % 10; // выделили младший разряд
N=N/10; // получили двузначное число
n2=N % 10; // опять выделили младший разряд
N = N/10; // получили однозначное число
n1=N; // заносим число в ячейку
printf("%d %d %d\n", n1, n2, n3);
return 0;
}

Для произвольного натурального числа сложность применения этого алгоритма в том, что мы заранее не знаем, сколько в нем цифр (разрядов), т.е. сколько отдельных ячеек понадобится. Для таких задач в языке Си есть структуры данных, которые называются массивы. Но мы пока можем обойтись без них. А вот сумму цифр любого целого числа найти можно и без массива. Для этого понадобится цикл типа while (почему?) и еще одна ячейка, в которой будем накапливать сумму. Фрагмент программного кода следующий:

int N, n; // N - число, n - рабочая переменная
int S=0; // S - будущая сумма, надо обнулить
printf("\nВведите число\n");
scanf("%d", &N);
while( N>0 ) // делать, пока N>0
{
n = N % 10; // получили цифру
S=S+n; // сумма накапливается
N = N / 10; // число сокращается
}
printf("Сумма цифр равна %d\n", S);

Во второй строчке кода отводится память под переменную S и тут же выполняется присваивание. Такой прием называется инициализация переменных. Занести в ячейку ноль, в которой накапливается сумма, обязательно (а почему?). Заодно подумаем, как инициализировать ячейку, если в ней накапливать произведение? Совершенно верно, единицей.









Последнее изменение этой страницы: 2016-04-07; Нарушение авторского права страницы

infopedia.su не принадлежат авторские права, размещенных материалов. Все права принадлежать их авторам. Обратная связь