C++ для начинающих

5.5. Инструкция цикла 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; ...
for ( char *ptr = getStr(); ...

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

(... index < arraySize; ... )
(... iter != ivec.end(); ... )
(... *stl++ = *st2++; ... )
(... char ch = getNextChar(); ... )

Выражение вычисляется после выполнения инструкции на каждой итерации цикла. Обычно его используют для модификации переменной, инициализированной в инструкции-инициализации. Если самое первое вычисление условия дает false, выражение не выполняется ни разу. Правильные выражения выглядят таким образом:

( ... ...; ++-index )
( ... ...; ptr = ptr->next )
( ... ...; ++i, --j, ++cnt )
( ... ...; ) // пустое выражение

Для приведенного ниже цикла for

const int sz = 24;
int ia[ sz ];
vector<int> ivec( sz );

for ( int ix = 0; ix < sz; ++ix ) {
ivec[ ix ] = ix;
ia[ ix ]= ix;
}

порядок вычислений будет следующим:

  1. инструкция-инициализации выполняется один раз перед началом цикла. В данном примере объявляется переменная ix, которая инициализируется значением 0.
  2. Вычисляется условие. Если оно равно true, выполняется составная инструкция тела цикла. В нашем примере, пока ix меньше sz, значение ix присваивается элементам ivec[ix] и ia[ix]. Когда значением условия станет false, выполнение цикла прекратится. Если самое первое вычисление условия даст false, составная инструкция выполняться не будет.
  3. Вычисляется выражение. Как правило, его используют для модификации переменной, фигурирующей в инструкции-инициализации и проверяемой в условии. В нашем примере ix увеличивается на 1.

Эти три шага представляют собой полную итерацию цикла 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 >::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 vector<int> &vl,
const vector<int> &v2 );

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

Назад   Вперед
Содержание




Нет комментариев.



Оставить комментарий:
Ваше Имя:
Email:
Антибот: *  
Ваш комментарий: