Глаза страшат, а руки делают

ЧАСТЬ ПЕРВАЯ


7. Операторы цикла: while, do...while

  • конвертируем арифметическую прогрессию;
  • таблица умножения: for внутри while;
  • таблица умножения в «слоёном» while;
  • оператор do...while

Оператор while

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

То же и в программировании. С помощью цикла while можно делать всё то же, что и с помощью цикла for. Что-то удобнее делать в одном цикле, что-то — в другом. Что-то быстрее в одном, что-то безопаснее в другом. Кто-то привык к одному, кто-то — к другому.

Чтобы Вам было понятнее, мы будем использовать те же самые примеры, но в новой «аранжировке».

While означает «в то время как» или «до тех пор, пока». В то время как имеется условие и до тех пор, пока оно существует, выполняется код.

Синтаксис до боли знакомый:

while (условие)
{код}

Попробуем «проиграть» в этом цикле наш первый пример: сумму чисел от 1 до 10. Вот как выглядят оба кода:

В цикле for значение счётчика i задавалось в заголовке цикла. В цикле while оно не задаётся, мы задаём его при объявлении переменной.

Шаг здесь переносится в самый конец. То есть мы задаём условие, назначаем на него действие и только потом указываем шаг для его выполнения.

Расширенный вариант, с выводом всех значений и блоком if для разделителей, попробуйте конвертировать сами. А потом взгляните на ответ.

А теперь немножко помучаемся с таблицей умножения.

Здесь у нас были вложенные циклы. Цикл while тоже можно вкладывать, но мы наткнёмся на один нюанс, связанный с последовательностью действий и сохранением данных в переменной, и придётся немножко обмануть программу.

А сначала попробуем комбинированный вариант: внешний цикл сконвертируем в while, а внутренний оставим for.

Вот наш внешний цикл, выводящий <tr>.

var i = 2, j;  // Сразу объявим переменную и для внутреннего цикла.
// Назначать не будем, так как внутренний цикл у нас FOR.
document.write("<table border='1' cellspacing='0' cellpadding='2'
align='center'>")
while (i <= 10)
{ document.write("<tr>")
    // Здесь будет
    // вложенный цикл.
document.write("<tr>")
i++
}
document.write("</table>")

Теперь просто скопируем в отведённое место вложенный цикл for:

var i = 2, j;
document.write("<table border='1' cellspacing='0' cellpadding='2'
align='center'>")
while (i <= 10)
{ document.write("<tr>")
    for (j = 2; j < 10; j++)
    {document.write("<td>" + j + "&times;" + i + "=" + (i * j) + "</td>")}
document.write("<tr>")
i++
}
document.write("</table>")

Теперь разберёмся с проблемой вложенных циклов while. Сейчас я приведу неправильный скрипт, и попробуем понять, почему он неправильный и как его исправить. Это будет неплохая разминка для мозгов.

var i = 2, j = 2;
document.write("<table border='1' cellspacing='0' cellpadding='2'
align='center'>")
while (i <= 10)
{ document.write("<tr>")
    while (j < 10)
    {document.write("<td>" + j + "&times;" + i + "=" + (i * j) + "</td>")
    j++
    }
document.write("<tr>")
i++
}
document.write("</table>")

Можете скопировать и запустить. Вы увидите заполненную первую строку и какую-то белую полоску под ней. Эта полоска — результат сгенерированных пустых <tr>. То есть внешний цикл честно отрабатывает до конца, а вложенный виснет на первом круге.

Вопрос: чему равна переменная j после первого прохождения большого цикла?

Ответ: она равна 10.

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

Ответ: 2, как задано.

Вопрос: как её сбросить?..

Давайте подумаем.

Есть оператор break, который мы использовали в switch. Здесь он тоже используется (потом мы о нём специально поговорим). Но сразу скажу, нашей беде он не поможет. С его помощью можно только поменять циклы (то есть будет выводиться только один вертикальный столбец).

Внимание. Думаем. Вникаем. Нам нужна переменная, которая бы содержала неизменную двойку. И нам нужна переменная, которая бы многократно проходила цикл от этой двойки. А что нам мешает создать ещё одну переменную, допустим, k, приравнять её к j и запустить в цикл? Да ничего, разве что тормоза в голове.

Смотрите, она (k) пройдёт цикл, прирастая до 10, а в следующем витке вновь приравняется к неизменной j и снова пройдёт тот же цикл:

var i = 2, j = 2, k;
document.write("<table border='1' cellspacing='0' cellpadding='2'
align='center'>")
while (i <= 10)
{ document.write("<tr>")
    k = j
    while (k < 10)
    {document.write("<td>" + k + "&times;" + i + "=" + (i * k) + "</td>")
    k++
    }
document.write("<tr>")
i++
}
document.write("</table>")

Вывод: лучше, всё-таки, использовать for. Но чтобы это понять, надо попробовать и while.

Примечание

Один из моих читателей, Игорь Кретов, написал работающий скрипт без дополнительной переменной и привёл его в моей гостевой книге:

var i = 2, j; // обратите внимание на неназначенную j (А.Ф.)
document.write("<table border='5'>")
while (i <= 10)
{ document.write("<tr>")
j = 2 // и только здесь j получает значение (А.Ф.)
    while (j < 10)
    {document.write("<td>" + j + "×" + i + "=" + (i * j) + "</td>")
    j++
    }
document.write("</tr>")
i++
}
document.write("</table>")

Мой комментарий

Этот комментарий я уже дал в скрипте. Теперь более подробно:
В своём скрипте я в самом начале задаю значения обеим переменным-счётчикам. Для сбрасывания j к 2 требуется новая переменная k. Игорь мудро оставляет j пустой, а задаёт ей значение только внутри первого цикла, и теперь при его прохождении она будет сбрасываться сама.
Признаю, что вариант Игоря изящнее.

Оператор do...while

Этот оператор очень похож на предыдущий. Различие, образно говоря, такое: если while сначала подумает, а потом сделает, то do...while сначала сделает, а потом подумает.

while

do...while

while (условие) проверяет
{код}           делает
do {код}        делает
while (условие) проверяет

Если оператор while не найдёт нужного условия при проверке, то его код вообще не будет выпонняться. А код оператора do...while хотя бы один раз выполняется всегда. А выполнение (или невыполнение) дальнейшего цикла уже зависит от проверки условия.

Ниже приводится сравнение кодов выведения нашей арифметической прогрессии в этих двух операторах.

А вот «аранжировка для do...while» нашей таблицы умножения (здесь тоже приходится использовать «лишнюю» переменную):

var i = 2, j = 2, k;
document.write("<table border='1' cellspacing='0' cellpadding='2'
align='center'>")
do
{document.write("<tr>")
    k = j
    do
    {document.write("<td>" + k + "&times;" + i + "=" + (i * k) + "</td>")
    k++
    }
    while (j < 10)
document.write("<tr>")
i++
}
while (i <= 10)
document.write("</table>")

Примечание

Вариант по И. Кретову без дополнительной переменной:

var i = 2, j;
document.write("<table border='1' cellspacing='0' cellpadding='2'
align='center'>")
do
{document.write("<tr>")
    j = 2
    do
    {document.write("<td>" + j + "&times;" + i + "=" + (i * j) + "</td>")
    j++
    }
    while (j < 10)
document.write("</tr>")
i++
}
while (i <= 10)
document.write("</table>")

В общем-то, мы закончили наше первое знакомство с операторами. Но есть ещё некоторые ключевые слова, вроде уже встречавшихся нам break или default. Это, по сути дела, тоже маленькие вспомогательные операторы, и им мы посвятим следующий урок, прежде чем перейдём к массивам.


Итак, мы узнали:

как работают циклы while и do...while, как переписать код для из одного цикла в другой.

А также:

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


К следующему уроку >>


 008407