Язык Си - руководство для начинающих.
ЦИКЛ while.
В предшествующих главах мы интенсивно пользовались этой формой цикла, сейчас же хотим рассмотреть его работу в случае простой, возможно, даже примитивной программы, угадывающей число.
/* угадывание числа1 */
/* неэффективный способ угадывания */
#inlude.
main( ).
{
Int guess = 1;
Char response;
Printf(" Задумайте целое число от 1 до 100. Я попробую угадать");
Printf(" его.\n Отвечайте д, если моя догадка правильна и");
Printf(" \n н, если я ошибаюсь. \n");
Рintf("Итак ... ваше число %d?\n" , guess);
While((response = getchar( )) != 'д') /* получениеответа*/
if (response != ' \n') /* пропуск символа "новая строка" */
printf(" Ну, тогда оно равно %d?\n", ++guess);
Printf(" Я знала, что смогу сделать это!\n");
}
Обратите внимание на логику программы. Если вы отвечаете д, в программе осуществляется выход из цикла и переход на завершающий оператор печати. Программа просит вас отвечать и в случае, если ее догадка неверна, но фактически любой ответ, отличный от символа д, приводит к тому, что программа входит в цикл. Однако если введен символ "новая строка", то при данном прохождении тела цикла никаких операций не производится. Получение другого символа приводит к очередной попытке угадывания целого числа. (Что произошло бы в случае использования операции guess++ вместо операции ++guess?).
Строка if(response ! = '\n') позволяет программе игнорировать поступление постороннего символа "новая строка", когда вы нажмете клавишу [ввод].
В этом случае тело цикла while не нужно заключать в фигурные скобки, поскольку оператор if, хотя он и занимает две строки в программе, рассматривается как один оператор.
Вы, по-видимому, уже заметили, что это довольно "тупая" программа. Она написана правильно и решает поставленную задачу, но делает это крайне неэффективно. Данный пример показывает нам, что правильность написания - не единственный критерий, по которому необходимо оценивать программу. При этом очень важна ее эффективность. Мы вернемся к данной программе несколько позже и попытаемся ее немного улучшить.
В общем виде цикл while записывается так:
While(выражение) оператор.
В наших примерах в качестве выражений использовались условные выражения, но, вообще говоря, это могут быть выражения произвольного типа. В качестве оператора можно использовать простой оператор с символом "точка с запятой" в конце или составной оператор, заключенный в фигурные скобки. Если выражение истинно (т.е. в общем случае не равно нулю), то оператор, входящий в цикл while выполняется один раз, а затем выражение проверяется снова, а последовательность действий, состоящая из проверки и выполнения оператора, периодически повторяется до тех пор, пока выражение не станет ложным (или в общем случае равным нулю). Такой шаг называется "итерация". Данная структура аналогична структуре оператора if. Основное отличие заключается в том, что в операторе if проверка условия и (возможное) выполнение оператора осуществляется только один раз, а в цикле while эти действия производятся, вообще говоря, неоднократно.

РИС. 8.1. Структура цикла while.
Завершение цикла while.
Мы подошли к самому существенному моменту рассмотрения циклов while. При построении цикла while вы должны включить в него какие-то конструкции, изменяющие величину проверяемого выражения так, чтобы в конце концов оно стало ложным. В противном случае выполнение цикла никогда не завершится. Рассмотрим следующий пример:
Index = 1;
While(index < 5).
Printf("Доброе утро!\n");
Данный фрагмент программы печатает это радостное сообщение бесконечное число раз, поскольку в цикле отсутствуют конструкции, изменяющие величину переменной index, которой было присвоено значение 1.
Index = 1;
While(--index < 5).
Printf("Как колеблются старые атомы!\n");
И этот фрагмент программы работает ненамного лучше. Значение переменной index в нем изменяется, но в "неправильном" направлении! Единственным утешением здесь служит тот факт, что выполнение данного куска программы в конце концов завершится. Это произойдет, когда величина переменной index станет меньше наименьшего отрицательного числа, допустимого в системе.
Цикл while является "условным" циклом, использующим предусловие (т.е. условие на входе). Он называется условным, потому что выполнение оператора зависит от истинности условия, описываемого с помощью выражения. Действительно ли значение переменной index меньше 5? Является ли последний введенный символ признаком EOF? Подобное выражение задает предусловие, поскольку выполнение этого условия должно быть проверено перед началом выполнения тела цикла. В ситуации, аналогичной приведенной ниже, тело цикла не выполнится ни разу, потому что используемое условие с самого начала является ложным.
Index = 10;
While(index++ < 5).
Printf(" Желаю хорошо провести день.\n");
Измените первую строку на.
Index = 3;
И вы получите работающую программу.
АЛГОРИТМЫ И ПСЕВДОКОД.
А теперь вернемся к нашей "тупоумной" программе, угадывающей число. Недостаток этой программы кроется не в программировании самом по себе, а в "алгоритме", т.е. методе, используемом для отгадывания числа. Этот метод можно описать следующим образом: попросите пользователя задумать число компьютер начинает угадывание с 1 до тех пор пока догадка неверна, предлагаемое значение увеличивается на 1.
Эта запись, между прочим, служит примером "псевдокода" представляющего собой способ выражения смысла программ на разговорном языке и являющегося некоторым аналогом языка машины. Псевдокод очень эффективен при разработке логики программы. После того как логика покажется вам правильной, вы можете обратить основное внимание на детали перевода псевдокода на реальный язык программирования. Преимущество использования псевдокода состоит в том, что он позволяет сконцентрироваться на логике и структуре программы, не заботясь пока о способе перевода этих идей на язык машины. Если мы хотим улучшить программу, нам в первую очередь необходимо улучшить алгоритм. Один из методов заключается в том, чтобы выбрать число где-нибудь посередине между 1 и 100 (50 нам вполне подходит) и попросить пользователя ответить больше ли это число задуманного, меньше его или равно ему. Если он сообщает, что данное число слишком велико, то тем самым из рассмотрения немедленно исключаются все числа между 50 и 100. Следующей догадкой программы является число, выбранное где-то посередине между 1 и 49. И снова ответ на вопрос, велико или мало это число, позволит исключить из рассмотрения половину оставшихся возможных чисел; программа продолжает указанный процесс, быстро сужая поле поиска до тех пор, пока задуманное число не будет угадано. Давайте запишем эти логические рассуждения на псевдокоде. Пусть highest - максимально возможная величина отгадываемого числа, a lowest - его минимально возможное значение. Вначале этими величинами будут соответственно 100 и 1, поэтому алгоритм запишется следующим образом:
Установить highest равным 100.
Установить lowest равным 1.
Попросить пользователя задумать число.
Предложенное значение (guess) равно (highest + lowest)/2.
Пока догадка неверна, делать следующее:
{если предложенное значение велико, установить highest равным этому предложенному значению минус 1.
Если предложенное значение мало, установить lowest равным этому предложенному значению плюс 1.
Новое предложенное значение равно (highest + lowest)/2 }
Обратите внимание на логику алгоритма: если предложенное значение, равное 50, велико, то максимально возможная величина задуманного числа будет равна 49. Если же значение 50 мало, то минимально возможная величина числа будет равна 51.
Сейчас мы переведем текст, указанный выше, на язык Си. Полученная программа представлена на рис. 8.2.
/* угадывание числа2 */
/* более эффективный способ угадывания*/
#include.
#define HIGH 100.
#define LOW 1.
Main( ).
{
Int guess = (HIGH + LOW)/2;
Int highest = HIGH;
Int lowest = LOW;
Char response;
Printf(" Задумайте число от %d до %d. Я попробую", LOW, HIGH);
Printf(" угадать его.\n Отвечайте д, если моя догадка правильна,");
Printf(" б, если \n больше, и м, если");
Printf(" меньше.\n");
Printf(" Итак ... ваше число %d?\n" , guess);
While((response = getchar( )) != 'д').
{
if( response != '\n').
{
If (response == 'б').
{
/* уменьшение верхнего предела,
если предложенное значение слишком велико */
Highest = guess - 1;
Guess = (highest + lowest)/2;
Printf(" Гм ... слишком велико. Ваше число %d?\n", guess);
}
Else if(response == 'м').
{
/* увеличение нижнего предела,если.
предложенное значение слишком мало*/
Lowest = guess + 1;
Guess = (highest + lowest)/2;
Printf(" Гм ... слишком мало. Ваше число %d?\n" , guess);
}
Else.
{
/* подводите пользователя к правильному ответу */
Printf(" Я не понимаю; введите, пожалуйста, д,б");
Printf ("или м.\n");
}
}
Printf("Я знала, что смогу сделать это!\n");
}
РИС. 8.2. Программа, угадывающая число.
Наличие в программе завершающей части else предоставляет пользователю дополнительную возможность правильно ответить на стандартный "отклик" программы. Заметим также, что мы использовали символические константы, чтобы сделать процесс изменения диапазона чисел достаточно простым. Работает ли данная программа? Ниже приводятся результаты этого прогона. Задуманное число - 71.
Задумайте число от 1 до 100. Я попробую угадать его.
Отвечайте д, если моя догадка правильна б, если.
больше, и м, если меньше.
Итак ..., ваше число 50?
Я не понимаю: введите, пожалуйста, д,б или м.
М.
Гм ... слишком мало. Ваше число 75?
Б.
Гм ... слишком велико. Ваше число 62?
М.
Гм ... слишком мало. Ваше число 68?
М.
Гм ... слишком мало. Ваше число 71?
Д.
Я знала, что смогу сделать это!
Что может быть неправильного в этой программе? Мы реализовали в ней защиту от ошибок, вызванных тем, что пользователи могут указывать неверные символы, поэтому здесь не должно быть никаких проблем. Единственное, что может повлиять на правильность работы программы: если вы вместо м укажете б, или наоборот. К сожалению, не существует способа заставить пользователя говорить правду и не делать ошибок. Тем не менее, если вы заинтересованы в этом, можете предпринять некоторые шаги. (Например, если захотите поразить свою шестилетнюю племянницу.) Во-первых, обратите внимание на то, что наш способ требует самое большее семи попыток для угадывания любого числа. (Каждая попытка уменьшает число возможностей наполовину. За семь попыток можно угадать любое число в диапазоне от 1 до 27- 1, или 127, что вполне достаточно для работы в диапазоне или 1 до 100.) Вы можете модифицировать программу так, чтобы она подсчитывала число попыток, и если окажется, что оно превышает 7, то тогда можно вывести на печать сообщение с выражением недовольства, а затем восстановить первоначальные значения переменных highest, lowest и счетчика. Дополнительные изменения, которые можно внести в программу, заключаются в такой модификации операторов if, в результате которой допускался бы ввод как прописных, так и строчных букв.
Резюме: оператор while.
Оператор while определяет операции, которые циклически выполняются до тех пор, пока проверяемое выражение не станет ложным, или равным нулю. Оператор while - это цикл с предусловием; решение, выполнять ли в очередной раз тело цикла, принимается перед началом его прохождения. Поэтому вполне возможно, тело цикла не будет выполнено ни разу. Оператор, образующий тело цикла, может быть либо простым, либо составным.
While(выражение) оператор.
Выполнение оператора циклически повторяется до тех пор, пока выражение не станет ложным, или равным нулю.
ПРИМЕРЫ.
While(n++ < 100) printf(" %d %d \n",n, 2*n + 1);
While(fargo < 1000).
{
fargo = fargo + step; step = 2 * step;
}
В нашем последнем примере в цикле while используется "неопределенное" условие: мы не знаем заранее, сколько раз выполнится тело цикла перед тем, как выражение станет ложным. Во многих наших предыдущих примерах, однако, циклы while использовались для подсчета числа выполнении тела цикла. Ниже приведен краткий пример, который содержит подсчитывающий цикл.
Main( ).
{
int = 1; /* инициализация */
while (count <= NUMBER) /* проверка */
{
printf(" Будь моим Валентином !\n"); /*действие */
count++; /* увеличение счетчика */
}
}
Хотя цикл подобного типа прекрасно работает, это не лучший вариант его записи, поскольку операции, реализующие цикл, не собраны вместе. Рассмотрим этот вопрос более подробно. При организации цикла, когда его тело должно быть выполнено фиксированное число раз, осуществляются три операции: инициализация счетчика, сравнение его величины с некоторым граничным значением и увеличение значения счетчика при каждом прохождении тела цикла. Условное выражение, имеющееся в цикле while, берет на себя заботу о сравнении, а приращение значения счетчика осуществляется с помощью операции увеличения. Так же как это делалось раньше, можно объединить эти два действия в одно выражение, используя запись count++ <= NUMBER. Но инициализация счетчика осуществляется вне цикла, как, например, в нашем примере оператором count = 1;. При этом можно забыть о необходимости инициализации счетчика, а то, что может случиться, рано или поздно случается. Сейчас мы рассмотрим управляющий оператор, использование которого позволяет избежать этих проблем.
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
- 69.
- 70.
- 71.
- 72.
- 73.
- 74.
- 75.
- 76.
- 77.
- 78.
- 79.
- 80.
- 81.
- 82.
- 83.
- 84.
- 85.
- 86.
- 87.
- 88.
- 89.
- 90.
- 91.
- 92.
- 93.
- 94.
- 95.
- 96.
- 97.
- 98.
- 99.
- 100.
- 101.
- 102.
- 103.
- 104.
- 105.
- 106.
- 107.
- 108.
- 109.
- 110.
- 111.
- 112.
- 113.
- 114.
- 115.
- 116.
- 117.
- 118.
- 119.
- 120.
- 121.
- 122.
- 123.
- 124.
- 125.
- 126.
- 127.
- 128.
- 129.
- 130.
- 131.
- 132.
- 133.
- 134.
- 135.
- 136.
- 137.
- 138.
- 139.
- 140.
- 141.
- 142.
- 143.
- 144.
- 145.
- 146.
- 147.
- 148.
- 149.
- 150.
- 151.
- 152.
- 153.
- 154.
- 155.
- 156.
- 157.
- 158.
- 159.
- 160.
- 161.
- 162.
- 163.
- 164.
- 165.
- 166.
- 167.
- 168.
- 169.
- 170.
- 171.
- 172.
- 173.
- 174.
- 175.
- 176.
- 177.
- 178.
- 179.
- 180.
- 181.
- 182.
- 183.
- 184.
- 185.
- 186.
- 187.
- 188.
- 189.
- 190.
- 191.
- 192.
- 193.
- 194.
- 195.
- 196.
- 197.
- 198.
- 199.
- 200.
- 201.
- 202.
- 203.
- 204.
- 205.
- 206.
- 207.
- 208.
- 209.
- 210.
- 211.
- 212.
- 213.
- 214.
- 215.
- 216.
- 217.
- 218.
- 219.
- 220.
- 221.
- 222.
- 223.
- 224.
- 225.
- 226.
- 227.
- 228.
- 229.
- 230.
- 231.
- 232.
- 233.
- 234.
- 235.
- 236.
- 237.
- 238.
- 239.
- 240.
- 241.
- 242.
- 243.
- 244.
- 245.
- 246.
- 247.
- 248.
- 249.
- 250.
- 251.
- 252.
- 253.
- 254.
- 255.
- 256.
- 257.
- 258.
- 259.
- 260.
- 261.
- 262.
- 263.
- 264.
- 265.
- 266.
- 267.
- 268.
- 269.
- 270.
- 271.
- 272.
- 273.
- 274.
- 275.
- 276.
- 277.
- 278.
- 279.
- 280.
- 281.
- 282.
- 283.
- 284.
- 285.
- 286.
- 287.
- 288.
- 289.
- 290.
- 291.
- 292.
- 293.
- 294.
- 295.
- 296.
- 297.
- 298.
- 299.
- 300.
- 301.
- 302.
- 303.
- 304.
- 305.
- 306.
- 307.
- 308.
- 309.
- 310.
- 311.
- 312.
- 313.
- 314.
- 315.
- 316.
- 317.
- 318.
- 319.
- 320.
- 321.
- 322.
- 323.
- 324.
- 325.
- 326.
- 327.
- 328.
- 329.
- 330.
- 331.
- 332.
- 333.
- 334.
- 335.
- 336.
- 337.
- 338.
- 339.
- 340.
- 341.
- 342.
- 343.
- 344.
- 345.
- 346.
- 347.
- 348.
- 349.
- 350.
- 351.
- 352.
- 353.
- 354.
- 355.
- 356.
- 357.
- 358.
- 359.
- 360.
- 361.
- 362.
- 363.
- 364.
- 365.
- 366.
- 367.
- 368.
- 369.
- 370.
- 371.
- 372.
- 373.
- 374.
- 375.
- 376.
- 377.
- 378.
- 379.
- 380.
- 381.
- 382.
- 383.
- 384.
- 385.
- 386.
- 387.
- 388.
- 389.
- 390.
- 391.
- 392.
- 393.
- 394.
- 395.
- 396.
- 397.
- 398.
- 399.
- 400.
- 401.
- 402.
- 403.
- 404.
- 405.
- 406.
- 407.
- 408.
- 409.
- 410.
- 411.
- 412.
- 413.
- 414.
- 415.
- 416.
- 417.
- 418.
- 419.
- 420.