Цикл while в языке Pascal

Создано: 06.04.2026

Циклы настолько важны в программировании и используются в разных ситуациях, что, например, в Паскале их целых три. Это циклические операторы while...do..., repeat...until... и for...to...do.... На этом уроке мы рассмотрим первый из них, который является циклом с предусловием и по своему синтаксису похож на условный оператор if...then....

While с английского переводится как "пока, в то время как, покуда", do — "делать".

Вернемся к примеру из прошлого урока, в котором подсчитывалась сумма пяти чисел:

label number;
var i, n, sum: integer;
begin
    i := 0;
    sum := 0;

    number:
    if i < 5 then begin
        read(n);
        sum := sum + n;
        i := i + 1;
        goto number;
    end;    

    writeln('Сумма: ', sum);
end.
4 5 8 12 5
Сумма: 34

По большому счету код от установки метки (number:) до конца условного оператора уже представляет собой цикл. Ведь на самом деле когда компилятор переводит настоящий цикл в машинный код, там используются метки, потому что на низком уровне циклов нет. Но Pascal — высокоуровневый язык, поэтому имеет циклические операторы, скрывающие детали компьютерной реализации. Подобное делает язык удобнее, он становится ближе к естественному.

Чтобы в примере с суммой появился настоящий цикл, надо просто удалить строки с меткой и переходом к ней, слово if заменить на while, а слово then — на do:

var
    i, n, sum: integer;

begin
    i := 0;
    sum := 0;

    while i < 5 do begin
        read(n);
        sum := sum + n;
        i := i + 1;
    end;    

    writeln('Сумма: ', sum);
end.

Однако такая незначительная замена ключевых слов меняет принцип работы всей конструкции. Если тело условного оператора, когда в нем нет goto, выполнялось только один раз, то тело цикла может делать это множество раз. До тех пор, пока условие в его заголовке будет оставаться правдой. Представьте, что в конце цикла стоит оператор goto, перебрасывающий поток выполнения в заголовок цикла. Мы избавились от него, потому что есть как бы договоренность, что оператор цикла сделает этот переброс сам. Это часть его работы, обязанностей.

Условие выполнения цикла в какой-то момент должно стать ложным. Иначе цикл не сможет завершить свою работу, то есть произойдет зацикливание, и программа зависнет. Поскольку в момент выполнения цикла исполняются выражения только в его теле, то именно среди них должно быть хотя бы одно, которое меняет значение переменной из условия таким образом, чтобы в конце концов логическое выражение там перестало возвращать правду.

В нашей программе такую роль берет на себя переменная i. Сначала она равна нулю, после первого прохода по телу цикла ее значение увеличивается на 1 и становится равно 1. После второго снова увеличивается на 1, становится равно 2-м и так далее. Когда ее значение достигнет 5, выражение i < 5 вернет ложь, и поток выполнения "выпрыгнет" из заголовка цикла за пределы всего цикла.

Закомментируйте строку кода, в которой изменяется i. Запустите программу, произойдет зацикливание, и вы сможете вводить числа бесконечно. Чтобы остановить работу зациклившийся программы в командной оболочке надо нажать Ctrl + C. Будет ли при этом посчитана и выведена сумма? Почему?

While как цикл с предусловием может не выполнится ни разу. Это произойдет, если условие сразу окажется ложным. Так мы можем присвоить i в начале программы не 0, а 5.

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

var
    f: real;
    error: integer;
    s: string;

begin
    readln(s);
    val(s, f, error);

    while error <> 0 do begin
        writeln('Введите число!');
        readln(s);
        val(s, f, error);
    end;    

    writeln(sqrt(f):10:3);
end.

Здесь тело цикла может ни разу не выполнится, если пользователь сразу введет число правильно. Если это не так, то число будет запрашиваться до тех пор, пока не будет получено, то есть error станет равной нулю, и условие error <> 0 вернет ложь.

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

error := -1;

while error <> 0 do begin
    write('Введите число: ');
    readln(s);
    val(s, f, error);
end;    

writeln(sqrt(f):10:3);

Однако если мы хотим информировать о том, что пошло не так, программу придется вернуть в первоначальный вид или добавить проверку внутри цикла:

error := -1;

while error <> 0 do begin
    readln(s);
    val(s, f, error);
    if error <> 0 then
        writeln('Это не число! Попробуйте еще раз.')
end;    

writeln(sqrt(f):10:3);

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

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

Еще раз взглянем на последнюю программу и обратим внимание на то, что нам неизвестно количество повторов цикла на момент начала его выполнения. Это отличается от первого примера, где мы точно знали, что будет 5 повторов. Циклы, в которых количество повторов нельзя вычислить, не могут быть описаны циклическим оператором for. Поэтому while является универсальным циклом. For хорошо подходит там, где необходим счетчик.

Циклы также можно вкладывать друг в друга как это делается с условными операторами. При этом понять логику работы такого кода сложнее. Рассмотрим пример:

var
    rows, items, n, sum: integer;

begin
    write('Количество наборов: ');
    readln(rows);

    while rows > 0 do begin
        write('Количество чисел: ');
        read(items);
        sum := 0;
        while items > 0 do begin
            read(n);
            sum := sum + n;
            items := items - 1;
        end;
        writeln('Сумма: ', sum);
        rows := rows - 1;
    end;    
end.

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

Количество наборов: 3
Количество чисел: 4
4 3 2 7
Сумма: 16
Количество чисел: 5
10 23 50 0 12
Сумма: 95
Количество чисел: 2
120 333
Сумма: 453

Сколько всего в этой программе потребуется ввести чисел, если задать 5 наборов и в каждом будет по 4 числа?

Задания для дополнительной или самостоятельной работы:

  1. Обратите внимание, что в последней программе из урока значение переменной, которая используется в условии цикла меняется путем вычитания. Это говорит о том, что неважно, какие действия с такой переменной выполняются. Напишите программу, которая выводит на экран каждое пятое число из ряда от 0 до 100 включительно.
  2. Измените программу, которая вычисляет сумму пяти чисел так, чтобы у пользователя сначала спрашивалось, хочет ли он вычислить сумму пяти чисел или нет. Если нет, то код цикла и вывода суммы не должен выполняться.