Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
C++ для начинающих (Стенли Липпман) 3-е хххх.pdf
Скачиваний:
86
Добавлен:
30.05.2015
Размер:
5.92 Mб
Скачать

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

184

5. Инструкции

Мельчайшей независимой частью С++ программы является инструкция. Она соответствует предложению естественного языка, но завершается точкой с запятой (;), а не точкой. Выражение С++ (например, ival + 5) становится простой инструкцией, если после него поставить точку с запятой. Составная инструкция это последовательность простых, заключенная в фигурные скобки. По умолчанию инструкции выполняются в порядке записи. Как правило, последовательного выполнения недостаточно для решения реальных задач. Специальные

управляющие конструкции позволяют менять порядок действий в зависимости от некоторых условий и повторять составную инструкцию определенное количество раз. Инструкции if, if-else и switch обеспечивают условное выполнение. Повторение обеспечивается инструкциями цикла while, do-while и for.

5.1. Простые и составные инструкции

Простейшей формой является пустая инструкция. Вот как она выглядит:

; // пустая инструкция

Пустая инструкция используется там, где синтаксис С++ требует употребления инструкции, а логика программы нет. Например, в следующем цикле while, копирующем одну строку в другую, все необходимые действия производятся внутри круглых скобок (условной части инструкции). Однако согласно правилам синтаксиса С++ после while должна идти инструкция. Поскольку нам нечего поместить сюда (вся работа

while ( *string++ = inBuf++ )

уже выполнена), приходится оставить это место пустым:

; // пустая инструкция

Случайное появление лишней пустой инструкции не вызывает ошибки компиляции. Например, такая строка

ival = dval + sval;; // правильно: лишняя пустая инструкция

состоит из двух инструкций сложения двух величин с присваиванием результата переменной ival и пустой.

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

// простые инструкции

int ival = 1024; // инструкция определения переменной ival; // выражение

ival + 5; // еще одно выражение

Например:

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

185

ival = ival +5; // присваивание

Условные инструкции и инструкции цикла синтаксически требуют употребления единственной инструкции, связанной с ними. Однако, как правило, этого недостаточно. В таких случаях употребляются составные инструкции последовательность простых,

if ( ival0 > ival1 ) {

//составная инструкция, состоящая

//из объявления и двух присваиваний

int temp = ivalO; ivalO = ival1; ival1 = temp;

заключенная в фигурные скобки:

}

Составная инструкция может употребляться там же, где простая, и не нуждается в завершающей точке с запятой.

Пустая составная инструкция эквивалентна пустой простой. Приведенный выше пример

while ( *string++ = *inBuf++ )

с пустой инструкцией можно переписать так:

{} // пустая инструкция

Составную инструкцию, содержащую определения переменных, часто называют блоком. Блок задает локальную область видимости в программе идентификаторы, объявленные внутри блока (как temp в предыдущем примере), видны только в нем. (Блоки, области видимости и время жизни объектов рассматриваются в главе 8.)

5.2. Инструкции объявления

ВС++ определение объекта, например int ival;

рассматривается как инструкция объявления (хотя в данном случае более правильно было бы сказать определения). Ее можно использовать в любом месте программы, где разрешено употреблять инструкции. В следующем примере объявления помечены комментарием //#n, где n – порядковый номер.

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

186

#include <fstream> #include <string> #include <vector> int main()

{

string fileName; // #1

cout << "Введите имя файла: "; cin >> fileName;

if ( fileName.empty() ) { // странный случай

cerr << "Пустое имя файла. Завершение работы.\n"; return -1;

}

ifstream inFile( fileName.c_str() ); // #2 if ( ! inFile ) {

cerr << "Невозможно открыть файл.\n"; return -2;

}

 

string inBuf;

// #3

vector<

string > text; // #4

while (

inFile >> inBuf ) {

for

( int ix = 0; ix < inBuf .size(); ++ix ) // #5

//можно обойтись без ch,

//но мы использовали его для иллюстрации

if (( char ch = inBuf[ix] )=='.'){ // #6 ch = '_';

inBuf[ix] = ch;

}

text.push_back( inBuf );

}

if ( text.empty() ) return 0;

//одна инструкция объявления,

//определяющая сразу два объекта vector<string>::iterator iter = text.begin(), // #7

iend = text.end();

while ( iter != -iend ) { cout << *iter << '\n'; ++iter;

}

return 0;

}

Программа содержит семь инструкций объявления и восемь определений объектов. Объявления действуют локально; переменная объявляется непосредственно перед первым использованием объекта.

В 70-е годы философия программирования уделяла особое внимание тому, чтобы определения всех объектов находились в начале программы или блока, перед исполняемыми инструкциями. (В С, например, определение переменной не является инструкцией и обязано располагаться в начале блока.) В некотором смысле это была реакция на идиому использования переменных без предварительного объявления, чреватую ошибками. Такую идиому поддерживал, например, FORTRAN.

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

187

Поскольку в С++ объявление является обычной инструкцией, ему разрешено появляться в любом месте программы, где допустимо употребление инструкции, что дает возможность использовать локальные объявления.

Необходимо ли это? Для встроенных типов данных применение локальных объявлений является скорее вопросом вкуса. Язык их поощряет , разрешая объявлять переменные внутри условных частей инструкций if, if-else, switch, while, for. Те программисты, которые любят этот стиль, верят, что таким образом делают свои программы более понятными.

Локальные объявления становятся необходимостью, когда мы используем объекты классов, имеющие конструкторы и деструкторы. Если мы помещаем все объявления в начало блока или функции, происходят две неприятные вещи:

конструкторы всех объектов вызываются перед исполнением первой инструкции блока. Применение локальных объявлений позволяет размазатьрасходы на инициализацию по всему блоку;

что более важно, блок или функция могут завершиться до того, как будут действительно использованы все объявленные в начале объекты. Скажем, наша программа из предыдущего примера имеет два аварийных выхода: при вводе

пользователем пустого имени файла и при невозможности открыть файл с заданным именем. При этом последующие инструкции функции уже не выполняются. Если бы объекты inBuf и next были объявлены в начале блока,

конструкторы и деструкторы этих объектов в случае ненормального завершения функции вызывались бы совершенно напрасно.

Инструкция объявления может состоять из одного или более определений. Например, в

//одна инструкция объявления,

//определяющая сразу два объекта vector<string>::iterator iter = text.begin(),

нашей программе мы определяем два итератора вектора в одной инструкции: lend = text.end();

vector<string>::iterator iter = text.begin();

Эквивалентная пара, определяющая по одному объекту, выглядит так: vector<string>::iterator lend = text.end();

Хотя определение одного или нескольких объектов в одном предложении является скорее вопросом вкуса, в некоторых случаях например, при одновременном определении объектов, указателей и ссылок это может спровоцировать появление ошибок. Скажем, в следующей инструкции не совсем ясно, действительно ли программист хотел определить

указатель и объект или просто забыл поставить звездочку перед вторым

// то ли хотел определить программист?

идентификатором (используемые имена переменных наводят на второе предположение): string *ptrl, ptr2;