1 Циклы и выражения сравнения
2 Компьютеры предназначены не только для хранения данных. Они анализируют, объединяют, реорганизуют, извлекают, видоизменяют, экстраполируют, синтезируют данные или иным образом манипулируют ими. Случается, что компьютеры даже искажают или портят информацию, хотя мы и стараемся этого не допускать. Чтобы проделывать все эти замечательные преобразования, программам необходимы инструментальные средства, позволяющие выполнять повторяющиеся действия или принимать решения. И такие инструментальные средства в C++, безусловно, имеются.
3 Обзор возможностей цикла for Листинг 5.1. Программа forloop.cpp // forloop.cpp -- Краткий обзор возможностей цикла for #include using namespace std; int main() { int i; // Создание счетчика // Инициализация, проверка и обновление счетчика for (i = 0; i < 5; i++) cout « "C++ knows loops.\n"; cout « "C++ knows when to stop.\n"; return 0; }
4 Составные части цикла for Цикл for предоставляет способ пошагового выполнения повторяющихся действий. Элементы цикла for: o Присвоение начального значения o Проверка условия продолжения цикла o Выполнение операций внутри цикла o Обновление значения (значений), используемых для проверки
5 Составные части цикла for Действия, связанные с инициализацией, проверкой и обновлением переменной цикла, образуют заключенную в скобки область управления циклом, которая состоит из трех частей. Каждая часть является выражением, одно выражение от другого отделяется точками с запятой. Оператор, который расположен после области управления, образует тело цикла и выполняется до тех пор, пока условие продолжения цикла не становится ложным: for (инициализация; условие продолжения цикла; обновление переменной цикла) тело цикла Цикл for трактуется в синтаксисе C++ как единый оператор, хотя в его тело может входить один или более операторов.
6 Составные части цикла for В качестве условия продолжения цикла в C++ может применяться не только выражение сравнения, образующее значения типа "истина-ложь", а любое выражение, среда же C++ приводит результат его вычисления к типу bool. Например, результат вычисления выражения, равный 0, преобразуется в значение false типа bool, и цикл завершается. Если же результат вычисления выражения оказывается ненулевым, он преобразуется в значение true типа bool, и выполнение цикла продолжается.
7 Составные части цикла for Листинг 5.2. Программа numjest.cpp // num_test.cpp -- Использование сравнения чисел для проверки условия // продолжения цикла #include using namespace std; int main() { cout « "Enter the starting countdown value: "; int limit; cin » limit; int i ; for (i = limit; i; i--) // Выйти из цикла, когда i = 0 cout « "i = " « i « "\n"; cout « "Done now that i = " « i « "\n"; return 0 ; }
8 Составные части цикла for Ниже приведен результат выполнения программы: Enter the starting countdown value: 4 i = 4 i = 3 i = 2 i = 1 Done now that i = 0
9 Составные части цикла for Цикл for является циклом с входным условием (или с предусловием). Это означает, что условие продолжения цикла проверяется перед выполнением каждой итерации цикла. При этом тело цикла вообще не выполняется, если условие продолжения цикла ложно. Обновление переменной цикла происходит в конце цикла после выполнения его тела.
10 Изменение шага цикла Вместо i++ в качестве выражения обновления переменной цикла в данном случае используется выражение i = i + by, где by это выбираемая пользователем величина шага цикла. Листинг 5.5. Программа bigstep.cpp // bigstep.cpp пользователь указывает шаг итерации #include using namespace std; int main() { cout « "Enter an integer: "; int by; cin » by; cout « "Counting by " « by « "s:\n"; for (int i = 0; i < 100; i = i + by) cout « i « "\n" ; return 0; }
11 Изменение шага цикла Ниже приведен результат выполнения данной программы: Enter an integer: 17 Counting by 17s:
12 Доступ к символам строки с помощью цикла for Цикл for предоставляет непосредственный доступ поочередно к каждому символу строки. Например, программа из листинга 5.6 позволяет вводить строку, а затем отображать ее посимвольно в обратном порядке. При этом функция strlen() подсчитывает количество символов в строке, а затем это значение используется в выражении инициализации цикла для присвоения i значения позиции последнего символа в строке, не считая пустого символа. Для перемещения по строке в обратном порядке в данной программе используется оператор декремента, для проверки достижения в цикле первого элемента используется оператор сравнения "больше или равно" (>=).
13 Доступ к символам строки с помощью цикла for Листинг 5.6. Программа forstrlcpp // forstrl.cpp использование цикла for для обработки строк #include using namespace std; const int ArSize = 20; int main() { cout « "Enter a word: "; char word[ArSize]; cin » word; // отображение символов строки в обратном порядке for (int i = strlen(word) 1; i >= 0; i --) cout « word[i] ; cout « "\n"; return 0 ; }
14 Операторы инкремента (++) и декремента (--) операторы выполняют две чрезвычайно распространенные в цикле операции: увеличение и уменьшение счетчика цикла на 1, однако их возможности этим не ограничиваются. Существует две разновидности каждого из операторов: в префиксном варианте изменение значения выполняется до обработки операнда, как, например, в выражении ++х; а в постфиксном после, как, например, в выражении х++.
15 Операторы инкремента (++) и декремента (--) // plus_one.cpp оператор инкремента #include using namespace std; int main () { int a = 20; int b = 20; cout « "a = " « a « " : b = " « b « "\n" ; cout « "a++ = " « a++ « ": ++b = " « ++b « "\n" ; cout «"a = " « a « " : b = " « b « "\n" ; return 0; } Ниже приведен результат выполнения указанной программы: а = 20: b = 20 а++ = 20: ++b = 21 а = 21: b = 21
16 Операторы инкремента (++) и декремента (--) int х = 5; int у= ++х; // изменить значение х, а затем присвоить это значение у // у равно 6 и х равно 6 int z = 5; int у = z++; // присвоить значение у, а затем изменить значение z //у равно 5, a z равно 6
17 Комбинированные операторы присваивания В листинге 5.5 для обновления переменной цикла используется следующее выражение: i = i + by В языке C++ существует комбинированный оператор сложения и присваивания, который дает тот же результат и является более компактным: i += by Оператор += выполняет сложение двух своих операндов и присваивает полученный результат левому операнду
18 Комбинированные операторы присваивания Для каждой арифметической операции имеется соответствующий оператор присваивания (табл. 5.1), каждый из которых действует аналогично оператору +=. Таким образом, оператор к *= 10; заменяет текущее значение к увеличенным в 10 раз значением. Таблица 5.1. Комбинированные операторы присваивания Операция Действие (L левый операнд, R -- правый операнд) += L + R присваивается L -= L - R присваивается L *= L * R присваивается L /= L / R присваивается L %= L % R присваивается L
19 Составные операторы или блоки в C++ существует специальный синтаксический прием, позволяющий вставить в тело цикла сколько угодно операторов. Он заключается в использовании фигурных скобок для построения составного оператора или блока. Блок состоит из пары фигурных скобок и операторов, которые в них заключены, при этом с точки зрения синтаксиса блок считается единым оператором. Если внутри блока определить новую переменную, то эта переменная будет продолжать существовать до тех пор, пока программа выполняет операторы внутри блока. При выходе из блока область памяти, занимаемая переменной, высвобождается.
20 Оператор "запятая" (или дополнительные синтаксические приемы) Как видим, блок дает возможность вставить в обход общих правил два или несколько операторов в том месте, где синтаксис C++ допускает только один оператор. Оператор "запятая" обеспечивает аналогичную возможность для выражений, благодаря чему допускается использование двух выражений в том месте, где синтаксис C++ допускает только одно выражение. Допустим, что имеется цикл, в котором одна переменная увеличивается, а вторая уменьшается на 1 в каждой итерации. Обе операции было бы удобно выполнить при обновлении цикла for, однако синтаксис цикла допускает только одно выражение в этой части цикла. Решение подобной задачи состоит в применении оператора "запятая" для объединения двух выражений в одно: j++, i--// оба выражения считаются единым выражением с точки зрения синтаксиса
21 Оператор "запятая" (или дополнительные синтаксические приемы) // Программа forstr2. cpp обратная перестановка содержимого массива #include using namespace std; const int ArSize = 20; int main() { cout « "Enter a word: "; char word[ArSize]; сin » word; // фактическое изменение массива char temp ; int i, j; for (j = 0, i = strlen(word) 1; j < i; i--, j++) {// начало блока temp = word[i] ; word[i] = word[j]; word[j] = temp; }// конец блока cout « word « "\nDone\n";\nDone\n return 0; } Пример вывода программы: Enter a word: parts strap Done
22 Цикл while Цикл while представляет собой цикл for, область управления которого не содержит частей инициализации и обновления переменной цикла. У него имеется только условие продолжения цикла и тело: while (условие продолжения цикла) тело цикла Сначала программа проверяет условие продолжения цикла. Если в результате вычисления этого выражения получается логическое значение true, выполняются операторы в теле цикла. Подобно циклу for, тело данного цикла состоит из одного оператора или блока, определяемого парой фигурных скобок. После завершения выполнения тела цикла программа возвращается к условию продолжения цикла и вычисляет его еще раз. Если данное условие оказывается ненулевым, то программа снова выполняет тело цикла. Подобный цикл проверки и выполнения продолжается до тех пор, пока в результате вычисления выражения не получится логическое значение false.
23 Цикл while // while.cpp демонстрация цикла while #include using namespace std; const int ArSize = 20; int main() { char name[ArSize]; cout « "Your first name, please: "; cin » name; cout « "Here is your name, verticalized and ASCIIized:\n"; int i = 0;// приступить к обработке с начала строки while (name[i] != '\0) // завершить процесс по достижению конца строки { cout « name[i] « ": " « int(name[i]) « '\n'; i++;// не забывайте об этом действии } return 0 ; }
24 Цикл while Пример вывода программы: Your first name, please: Muffy Here is your name, verticalized and ASCIIized: M: 77 u: 117 f: 102 y: 121
25 Сравнение циклов for и while for (инициализация цикла; условие продолжения цикла; обновление переменной цикла) { оператор(ы) } может быть переписан следующим образом: инициализация цикла; while (условие продолжения цикла) { оператор(ы) обновление переменной цикла; }
26 Сравнение циклов for и while Аналогично цикл while: while (условие продолжения цикла) тело цикла может быть переписан следующим образом: for ( ; условие продолжения цикла; ) тело цикла
27 Сравнение циклов for и while Для цикла for необходимы три выражения (или, точнее, один оператор с двумя последующими выражениями), однако эти выражения (или операторы) могут быть пустыми. Обязательно лишь наличие двух точек с запятой. В этой связи пропуск условия продолжения в цикле for истолковывается как истинное значение, и поэтому цикл for ( ; ; ) тело цикла выполняется бесконечно.
28 Сравнение циклов for и while Как правило, программисты применяют цикл for в качестве цикла со счетчиком, поскольку формат цикла for позволяет размещать в одном месте все необходимые данные: начальное значение, конечное значение и способ обновления переменной цикла (счетчика цикла). А цикл while чаще всего применяется в том случае, когда количество подлежащих выполнению итераций заранее точно не известно. При разработке цикла необходимо: Определить условие, которое завершает выполнение цикла. Инициализировать переменную цикла до выполнения первой проверки. Обновлять переменную цикла в каждой итерации цикла перед повторной проверкой условия.
29 Цикл do while До этого момента мы с вами рассмотрели циклы for, и while. В C++ существует еще один тип цикла do while. От двух предыдущих он отличается тем, что обладает постусловием. Это означает, что сначала выполняется тело цикла и только после этого вычисляется выражение условия продолжения цикла. Если в результате получается логическое значение false, цикл завершается. В противном случае начинается новый этап выполнения и проверки условия. Подобный цикл всегда выполняется по крайней мере один раз, поскольку процесс выполнения программы должен пройти тело цикла, прежде чем будет осуществлена проверка условия продолжения. Ниже приведен синтаксис рассматриваемого цикла: do тело цикла while (условие продолжения цикла); Тело данного цикла может состоять из одного оператора или ограниченного фигурными скобками блока операторов.
30 Цикл do while // dowhile.cpp -- программа, демонстрирующая цикл с постусловием #include using namespace std; int main() { int n; cout « "Enter numbers in the range 1-10 to find "; cout « "my favorite number\n"; do { cin » n;// выполнить тело цикла } while (n != 7) ;// затем осуществить проверку cout « "Yes, 7 is my favorite.\n" ; return 0 ; } Enter numbers in the range 1-10 to find my favorite number Yes, 7 is my favorite.
31 Вложенные циклы и двумерные массивы Специального типа двумерных массивов в языке C++ не существует. Вместо этого создается массив, каждый элемент которого, в свою очередь, является массивом. Предположим, что требуется сохранить данные о максимальной температуре воздуха в пяти городах за четырехлетний период. В этом случае можно объявить следующий массив: int maxtemps[4][5] ; Это объявление означает, что maxtemps является массивом из четырех элементов. При этом каждый элемент данного массива представляет собой массив из пяти целочисленных значений. Таким образом, массив maxtemps можно рассматривать как состоящий из четырех строк, в каждой из которых приведено пять значений температуры.
32 Вложенные циклы и двумерные массивы для доступа к элементам двухмерного массива приходится использовать два индекса, первый из которых можно рассматривать как элемент, представляющий строку, а второй как элемент, представляющий столбец
33 Вложенные циклы и двумерные массивы Предположим, что требуется вывести содержимое всего массива. В этом случае для изменения строк можно воспользоваться одним циклом for, а для изменения столбцов вторым, вложенным циклом for: for (int row = 0; row < 4; row++) { for (int col = 0; col < 5; col++) cout « maxtemps[row][col] « "\t"; cout « "\n"; } Для каждого значения переменной row во внутреннем цикле for осуществляется поочередное обращение ко всем значениям переменной col.
34 Инициализация двумерного массива В основу данного метода положена инициализация одномерного массива. Напомним, что данный метод состоит в предоставлении разделенного запятыми списка значений, заключенных в фигурные скобки: // инициализация одномерного массива int btus[5] s { 23, 26, 24, 31, 28}; Что касается двумерного массива, то каждый его элемент сам является массивом, поэтому он может быть инициализирован приведенным выше способом. Таким образом, инициализация двумерного массива состоит из ряда инициализаций одномерных массивов, заключенных в фигурные скобки, с разделением запятыми: int maxtemps[4][5] = // Двумерный массив { {94, 98, 87, 103, 101},// Значения массива maxtemps[0] {98, 99, 91, 107, 105},// Значения массива maxtemps[l] {93, 91, 90, 101, 104},// Значения массива maxtemps[2] {95, 100, 88, 105, 103}// Значения массива max temps [3] };};
35 Инициализация двумерного массива В программе из листинга 5.19 применяется и двумерный массив, и вложенный цикл. Циклы используются в данной программе в обратном порядке, т.е. цикл обработки столбцов (индекс городов) оказывается внешним, а цикл обработки строк (индекс лет) внутренним. Здесь применяется распространенный в C++ метод инициализации массива указателей с присвоением значений набора строковых констант. Таким образом, cities объявляется в виде массива указателей типа char. При этом каждый элемент данного массива, в частности cities [0], является указателем типа char, который может быть инициализирован с присвоением адреса строки. Так, рассматриваемая программа инициализирует элемент ciities[0] с присвоением адреса строки "Gribble city" и т.д. Данный массив указателей, по существу, является массивом строк.
36 Инициализация двумерного массива // программа nested.cpp, демонстрирующая // возможности двумерных массивов и вложенных циклов #include using namespace std; const int Cities = 5; const int Years = 4; int main() { const char * cities [Cities] = // массив указателей на пять строк { "Gribble City", "Gribbletown", "New Gribble", "San Gribble", "Gribble Vista };
37 Инициализация двумерного массива int maxtemps[Years][Cities] = // двухмерный массив { {95, 99, 86, 100, 104}, //Значениямассиваmaxtemps[0] {95, 97, 90, 106, 102}, // Значения массиваmaxtemps[1] {96, 100, 940, 107, 105}, //Значениямассиваmaxtemps[2] {97, 102, 89, 108, 104} //Значениямассиваmaxtemps[3] } ; cout « "Maximum temperatures for \n\n; for (int city = 0; city < Cities; city++) { cout « cities[city] « :\t"; for (int year = 0; year < Years; year++) cout « maxtemps[year][city] « "\t"; cout « "\n"; } return 0 ; }
38 Инициализация двумерного массива Пример выполнения программы: Maximum temperatures for Gribble City: Gribbletown: New Gribble: San Gribble: Gribble Vista: