Выбрать главу

int main()

{

string word;

vector string text;

// ...

for ( vector string ::iterator

iter = text.begin(),

iter_end = text.end();

iter != text.end(); ++iter )

{

if ( *iter == word )

break;

// ...

}

// ошибка: iter и iter_end невидимы

if ( iter != iter_end )

// ...

Упражнение 5.8

Допущены ли ошибки в нижеследующих циклах for? Если да, то какие?

(a)

for ( int *ptr = ia, ix = 0;

ix size ptr != ia+size;

++ix, ++ptr )

// ...

(b)

for ( ; ; ) {

if ( some_condition )

break;

// ...

}

(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.10

Дано объявление функции:

bool is_equa1( const vectorint vl,

const vectorint v2 );

Напишите тело функции, определяющей равенство двух векторов. Для векторов разной длины сравнивайте только то количество элементов, которое соответствует меньшему из двух. Например, векторы (0,1,1,2) и (0,1,1,2,3,5,8) считаются равными. Длину векторов можно узнать с помощью функций v1.size() и v2.size().

5.6. Инструкция while

Синтаксис инструкции while следующий:

while ( условие )

инструкция

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

* Вычислить условие.

* Выполнить инструкцию, если условие истинно.

* Если самое первое вычисление условия дает 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;

}

int ia[6] = { 0, 1, 2, 3, 4, 5 };

int main()

{

int sum = sumit( ia[0], ia[ 6 ] );

// ...

}

Для того чтобы функция sumit() выполнялась правильно, оба указателя должны адресовать элементы одного и того же массива (parray_end может указывать на элемент, следующий за последним). В противном случае sumit() будет возвращать бессмысленную величину. Увы, С++ не гарантирует, что два указателя адресуют один и тот же массив. Как мы увидим в главе 12, стандартные универсальные алгоритмы реализованы подобным же образом, они принимают параметрами указатели на первый и последний элементы массива.

Упражнение 5.11

Какие ошибки допущены в следующих циклах while:

(a)

string bufString, word;

while ( cin bufString word )

// ...

(b)

while ( vectorint::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.12

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

Упражнение 5.13