С.Б. Липпман, Ж. Лажойе - Язык программирования С++ Вводный курс (1114944), страница 36
Текст из файла (страница 36)
Инструкция цикла forКак мы видели, выполнение программы часто состоит в повторении последовательностиинструкций – до тех пор, пока некоторое условие остается истинным. Например, мычитаем и обрабатываем записи файла, пока не дойдем до его конца, перебираем элементымассива, пока индекс не станет равным размерности массива минус 1, и т.д. В С++предусмотрено три инструкции для организации циклов, в частности for и while,которые начинаются проверкой условия. Такая проверка означает, что цикл можетзакончиться без выполнения связанной с ним простой или составной инструкции. Третийтип цикла, do while, гарантирует, что тело будет выполнено как минимум один раз:условие цикла проверяется по его завершении.
(В этом разделе мы детально рассмотримцикл for; в разделе 5.6 разберем while, а в разделе 5.7 – do while.)Циклforобычноиспользуетсядляобработкиструктурданных,имеющих#include <vector>int main() {int ia[ 10 ];for ( int ix = 0; ix < 10; ++-ix )ia[ ix ] = ix;vector<int> ivec( ia, ia+10 );vector<int>::iterator iter = ivec.begin() ;for ( ; iter != ivec.end(); ++iter )*iter *= 2;return 0;фиксированную длину, таких, как массив или вектор:}for (инструкция-инициализации; условие; выражение )Синтаксис цикла for следующий:инструкцияинструкция-инициализации может быть либо выражением, либо инструкциейобъявления. Обычно она используется для инициализации переменной значением,которое увеличивается в ходе выполнения цикла.
Если такая инициализация не нужнаили выполняется где-то в другом месте, эту инструкцию можно заменить пустой (см.второй из приведенных ниже примеров). Вот примеры правильного использования// index и iter определены в другом местеfor ( index =0; ...for ( ; /* пустая инструкция */ ...for ( iter = ivec.begin(); ...for ( int 1o = 0,hi = max; ...инструкции-инициализации:С++ для начинающих206for ( char *ptr = getStr(); ...условие служит для управления циклом. Пока условие при вычислении дает true,инструкция продолжает выполняться. Выполняемая в цикле инструкция может быть какпростой, так и составной.
Если же самое первое вычисление условия дает false,(... index < arraySize; ... )(... iter != ivec.end(); ... )(... *stl++ = *st2++; ... )инструкция не выполняется ни разу. Правильные условия можно записать так:(... char ch = getNextChar(); ... )Выражение вычисляется после выполнения инструкции на каждой итерации цикла.Обычно его используют для модификации переменной, инициализированной винструкции-инициализации. Если самое первое вычисление условия дает false,( ...( ...( ......; ++-index )...; ptr = ptr->next )...; ++i, --j, ++cnt )выражение не выполняется ни разу. Правильные выражения выглядят таким образом:( ......; ) // пустое выражениеconst int sz = 24;int ia[ sz ];vector<int> ivec( sz );for ( int ix = 0; ix < sz; ++ix )ivec[ ix ] = ix;ia[ ix ]= ix;{Для приведенного ниже цикла for}порядок вычислений будет следующим:1.
инструкция-инициализации выполняется один раз перед началом цикла. В данномпримере объявляется переменная ix, которая инициализируется значением 0.2. Вычисляется условие. Если оно равно true, выполняется составная инструкция телацикла. В нашем примере, пока ix меньше sz, значение ix присваивается элементамivec[ix] и ia[ix]. Когда значением условия станет false, выполнение циклапрекратится. Если самое первое вычисление условия даст false, составнаяинструкция выполняться не будет.3. Вычисляется выражение. Как правило, его используют для модификациипеременной, фигурирующей в инструкции-инициализации и проверяемой вусловии.
В нашем примере ix увеличивается на 1.С++ для начинающих207Эти три шага представляют собой полную итерацию цикла for. Теперь шаги 2 и 3 будутповторяться до тех пор, пока условие не станет равным false, т.е. ix окажется равнымили большим sz.В инструкции-инициализации можно определить несколько объектов, однако все ониfor ( int ival = 0, *pi = &ia, &ri = val;ival < size;++iva1, ++pi, ++ri )должны быть одного типа, так как инструкция объявления допускается только одна:// ...Объявление объекта в условии гораздо труднее правильно использовать: такоеобъявление должно хотя бы раз дать значение false, иначе выполнение цикла никогда#include <iostream>int main(){for ( int ix = 0;bool done = ix == 10;++ix )cout << "ix: " << ix << endl;не прекратится.
Вот пример, хотя и несколько надуманный:}Видимость всех объектов, определенных внутри круглых скобок инструкции for,ограничена телом цикла. Например, проверка iter после цикла вызовет ошибкуint main(){string word;vector< string > text;// ...for ( vector< string >::iteratoriter = text.begin(),iter_end = text.end();iter != text.end(); ++iter ){if ( *iter == word )break;// ...}// ошибка: iter и iter_end невидимыif ( iter != iter_end )компиляции8:8 До принятия стандарта языка С++ видимость объектов, определенных внутри круглыхскобок for, простиралась на весь блок или функцию, содержащую данную инструкцию.Например, употребление двух циклов for внутри одного блокаПримечание [O.A.2]: Нумерация сносок сбита, как и всяостальная. Необходима проверка.С++ для начинающих// ...Упражнение 5.8(a)for ( int *ptr = &ia, ix = 0;ix < size && ptr != ia+size;++ix, ++ptr )// ...Допущены ли ошибки в нижеследующих циклах for? Если да, то какие?(b)for ( ; ; ) {if ( some_condition )break;// ...}{// верно для стандарта С++// в предыдущих версиях C++ - ошибка: ival определена дваждыfor (int ival = 0; ival < size; ++iva1 ) // ...for (int ival = size-1; ival > 0; ival ) // ...}в ранних версиях языка вызывало ошибку: ival определена дважды.
В стандарте С++данный текст синтаксически правилен, так как каждый экземпляр ival являетсялокальным для своего блока.208С++ для начинающих209(c)for ( int ix = 0; ix < sz; ++ix )// ...if ( ix != sz )// ...(d)int ix;for ( ix < sz; ++ix )// ...(e)for ( int ix = 0; ix < sz; ++ix, ++ sz )// ...Упражнение 5.9Представьте, что вам поручено придумать общий стиль использования цикла for ввашем проекте.
Объясните и проиллюстрируйте примерами правила использованиякаждой из трех частей цикла.Упражнение 5.10bool is_equa1( const vector<int> &vl,Дано объявление функции:const vector<int> &v2 );Напишите тело функции, определяющей равенство двух векторов. Для векторов разнойдлины сравнивайте только то количество элементов, которое соответствует меньшему издвух. Например, векторы (0,1,1,2) и (0,1,1,2,3,5,8) считаются равными. Длину векторовможно узнать с помощью функций v1.size() и v2.size().5.6. Инструкция whilewhile ( условие )Синтаксис инструкции while следующий:инструкцияПока значением условияпоследовательности:являетсяtrue,инструкция1. Вычислить условие.2. Выполнить инструкцию, если условие истинно.выполняетсявтакойС++ для начинающих3.
Если самое первое вычисление условия дает false, инструкция не выполняется.bool quit = false;// ...while ( ! quit ) {// ...quit = do_something();}string word;Условием может быть любое выражение:while ( cin >> word ){ ... }while ( symbol *ptr = search( name )) {// что-то сделатьили объявление с инициализацией:}В последнем случае ptr видим только в блоке, соответствующем инструкции while, какэто было и для инструкций for и switch.Вот пример цикла while, обходящего множество элементов, адресуемых двумяint sumit( int *parray_begin, int *parray_end ){int sum = 0;if ( ! parray_begin || ! parray_end )return sum;while ( parray_begin != parray_end )// прибавить к sum// и увеличить указательsum += *parray_begin++;return sum;}intint{ia[6] = { 0, 1, 2, 3, 4, 5 };main()int sum = sumit( &ia[0], &ia[ 6 ] );// ...указателями:}Для того чтобы функция sumit() выполнялась правильно, оба указателя должныадресовать элементы одного и того же массива (parray_end может указывать наэлемент, следующий за последним).
В противном случае sumit() будет возвращатьбессмысленную величину. Увы, С++ не гарантирует, что два указателя адресуют один и210С++ для начинающих211тот же массив. Как мы увидим в главе 12, стандартные универсальные алгоритмыреализованы подобным же образом, они принимают параметрами указатели на первый ипоследний элементы массива.Упражнение 5.11(a)string bufString, word;while ( cin >> bufString >> word )Какие ошибки допущены в следующих циклах while:(b)while ( vector<int>::iterator iter !=// ...ivec.end() )(c)while ( ptr = 0 )ptr = find_a_value();(d)while ( bool status = find( word )) {word = get_next_word();if ( word.empty() )break;// ...}if ( ! status )// ...cout << "Слов не найдено\n";Упражнение 5.12while обычно применяется для циклов, выполняющихся, пока некоторое условиеистинно, например, читать следующее значение, пока не будет достигнут конец файла.for обычно рассматривается как пошаговый цикл: индекс пробегает по определенномудиапазону значений.
Напишите по одному типичному примеру for и while, а затемизмените их, используя цикл другого типа. Если бы вам нужно было выбрать дляпостоянной работы только один из этих типов, какой бы вы выбрали? Почему?Упражнение 5.13Напишите функцию, читающую последовательность строк из стандартного ввода до техпор, пока одно и то же слово не встретится два раза подряд либо все слова не будутобработаны. Для чтения слов используйте while; при обнаружении повтора словазавершите цикл с помощью инструкции break. Если повторяющееся слово найдено,напечатайте его. В противном случае напечатайте сообщение о том, что слова неповторялись.С++ для начинающих5.8.
Инструкция do whileПредставим, что нам надо написать программу, переводящую мили в километры.int val;bool more = true; // фиктивное значение, нужное для// начала циклаwhile ( more ) {val = getValue();val = convertValue(val);printValue(val);more = doMore();Структура программы выглядит так:}Проблема заключается в том, что условие вычисляется в теле цикла. for и whileтребуют, чтобы значение условия равнялось true до первого вхождения в цикл, иначетело не выполнится ни разу.