Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Паппас К., Мюррей У. - Visual C++ 6. Руководство разработчика - 2000

.pdf
Скачиваний:
288
Добавлен:
13.08.2013
Размер:
4.96 Mб
Скачать

\n\t\t3 - МЕТРЫ \ \n\n\t\tBaш выбор — >> "); scanf("%d",&iuser_response) ; switch (iuser_response) (

case 0 : C_Tconversion = YARDS;

break; case 1 : C_Tconversion = INCHES; break; case 2 : C_Tconversion = CENTIMETERS; break; default : C_Tconversion = METERS;

if (C_Tconversion == YARDS)

fmeasurement = ffoot/3; else if (C_Tconversion == INCHES) fmeasurement = ffoot * 12; else if (C_Tconversion == CENTIMETERS) fmeasurement = ffoot * 30.48; else

fmeasurement = ffoot * 30.48/100; switch (C Tconversion) {

case

YARDS

: printf("\n\t\t%4.2f

ярдов", fmeasurement); break;

case

INCHES

: printf("\n\t\t%4.2f

дюймов", fmeasurement);

break;

 

 

case CENTIMETERS :

printf("\n\t\t%4.2f сантиметров", fmeasure'ment) ; break;

default :

printf("\n\t\t%4.2f метров", fmeasurement); } return (0);

}

В данном примере константы единиц измерений представлены перечислением conversion_type. (Подробнее о перечислениях см. в главе "Дополнительные типы данных".) Первый блок switch/case предназначен для того, чтобы на основании введенного пользователем значения проинициализировать переменную C_Tconversion типа conversion_type. Затем в блоке вложенных инструкций if/else/if выполняется соответствующее преобразование. Наконец, в последнем блоке switch/case полученное значение выводится на экран.

Циклы

В языках С и C++ используются стандартные циклические инструкции: for, while и do/while(в некоторых языках программирования высокого уровня последняя называется repeat/until). Особенностью этих языков является то, что они располагают средствами прерывания циклов. Обычно цикл продолжается до тех пор, пока не выполнится некоторое условие, заданное при инициализации цикла. Но в C/C++ цикл можно прервать после обнаружения ожидаемой ошибки или по другой причине с помощью инструкции break. Кроме того, допускается принудительный переход на следующую итерацию цикла с помощью инструкции continue.

Отличие цикла for от циклов while и do/while состоит в том, что в нем, как правило, число повторений заранее известно. Таким образом, цикл for обычно используется в тех случаях, когда можно точно определить необходимое количество повторов. Циклы while и do/while применяются, когда число повторений неизвестно, но имеется некоторое условие, которое необходимо выполнить.

Цикл for

Цикл for имеет следующий синтаксис:

for(инициализирующее_выражение;. условное_выражение; модифицирующее_выражение) выражение;

При обнаружении в программе цикла for первым выполняется инициализирующее_выражение, в котором обычно устанавливается счетчик цикла. Это происходит только один раз перед запуском цикла. Затем анализируется условное_выражение, которое также называется условием прекращения цикла. Пока оно равно true, цикл не прекращается. Каждый раз после всех строк тела цикла выполняется модифицирующее_выражение, в котором происходит

101

изменение счетчика цикла. Как только проверка условного_выражения даст результат false, все строки тела цикла и модифицирующее_выражение будут пропущены и управление будет передано первому выражению, следующему за телом цикла. Если тело цикла содержит более одной команды, следует использовать фигурные скобки и руководствоваться определенными правилами оформления, чтобы сделать текст программы более понятным: for (инициализирующее_выражение; условное_выражение; модифицирукщее_выражение) { выражение1;

выражение2; выражениеЗ; выражение-n; }

Давайте рассмотрим некоторые примеры использования цикла for. В следующем фрагменте вычисляется сумма ряда целых чисел от 1 до 5. Предполагается, что переменные isum и ivalue имеют тип int:

isum = 0;

for (ivalue = .1; ivalue <= 5; ivalue++) isum += ivalue;

Сначала переменной isum присваивается нулевое значение, после чего запускается цикл for, который начинается с присваивания переменной ivalue значения 1. Эта операция выполняется только один раз. Затем проверяется условие ivalue<= 5. Поскольку на первом шаге цикла это выражение равно true, к переменной isum прибавляется текущее значение переменной ivalue

— единица. По завершении выполнения последней строки цикла (в данном случае единственной) переменная ivalue увеличивается на единицу. Этот процесс будет повторяться до тех пор, пока значение переменной ivalue не достигнет 6, что приведет к завершению цикла.

В программе на языке C++ приведенный фрагмент будет записан следующим образом (найдите одно отличие):

isum = 0;

for (intivalue = 1; ivalue <= 5; ivalue-м-) isum += ivalue;

В C++ допускается объявление переменных прямо в строке инициализации цикла for. Тут затрагивается достаточно важный вопрос: где вообще следует размещать все объявления переменных? В C++ переменные можно создавать непосредственно перед той строкой, где они впервые используются. Поскольку в нашем случае переменная ivalue используется только внутри цикла, ее объявление в цикле не нарушает стройности программы. Но рассмотрим такой пример:

int isum = 0;

for(intivalue = i; ivalue <= 5; ivalue++) isum += ivalue;

Подобное объявление переменной isum можно назвать плохим стилем программирования, если ее применение не ограничивается данным циклом. Желательно все объявления локальных переменных собирать сразу после заголовка функции, к которой они относятся, так как это повышает удобочитаемость программы и облегчает ее отладку. Значение счетчика цикла for вовсе не обязательно должно меняться только на единицу. В следующем примере вычисляется сумма ряда нечетных чисел от 1 до 9:

iodd_sum = 0;

for(iodd_value = 1; iodd_value <— 9; iodd_value += 2); iodd_sum += iodd_value;

Здесь счетчиком цикла является переменная iodd_value, и ее значение на каждом шаге увеличивается на 2.

Кроме того, счетчик цикла может не только увеличиваться, но и уменьшаться, В следующем примере с помощью цикла for организуется считывание строки символов в массив саrrау, а затем с помощью другого цикла for эта строка выводится на экран в обратном порядке:

/*

*forloop.cpp

*В этой программе на языке C++ демонстрируется использование

* цикла for для работы с массивом символов. */

#include <stdio.h>

102

#define CARRAY_SIZE 10 int main()

{

int ioffset;

char carray[CARRAY_SIZE];

for(ioffset = 0; ioffset < CARRAY_SIZE; ioffset++)

carray[ioffset] = getchar(); for(ioffset = CARRAY_SIZE - 1; ioffset >= 0; ioffset—)

putchar(carray[ioffset]); return(0); }

В первом цикле for переменной ioffset присваивается начальное значение 0, поскольку адресация элементов массива начинается с нуля. Затем происходит считывание символов по одному до тех пор, пока значение переменной ioffset не станет равным размеру массива. Во втором цикле for, в котором элементы массива выводятся на экран в обратном порядке, переменная ioffset инициализируется номером последнего элемента массива и по ходу цикла уменьшается на единицу. Цикл будет выполняться до тех пор, пока переменная ioffset не примет значение 0.

При работе с вложенными циклами for обращайте внимание на правильную расстановку фигурных скобок, чтобы четко определить границы каждого цикла:

/*

*nsloopl.с

*В этой программе на языке С демонстрируется важность

*правильной расстановки фигурных скобок во вложенных циклах.

*/

#include <stdio.h> int main()

{

int iouter_val, iinner_val;

for (iouter_val = 1; iouter_val <= 4; iouter val++) ( printf ("\n%3d-- ",iouter_val) ;

for (iinner_val = 1; iinner_val <= 5; iinner_val++) printf ("%3d",iouter_val * iinner_val) ;

return(0); }

В результате выполнения программы будут выведены следующие данные:

1

12345..

 

 

 

2

— 2

4

6

8

10

3

— 3

б

9

12

15

4

4

8

12

16

20

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

/*

*nsloop2.c

*В этой программе на языке С демонстрируется, что произойдет, если

при

*задании внешнего цикла не поставить фигурные скобки.

*/

#include <stdio.h> int main ()

int iouter_val, iinner_val;

for(iouter_val = 1; iouter_val <= 4; iouter_val++) printf("\n%3d-", iouter_val);

for(iinner_val = >>1; iinner_val <= 5; iinner_val++) printf("%3d", iouter_val * iinner_val);

return(0);

Выводимые данные будут выглядеть совершенно иначе:

103

1--

2--

3--

4-- 5 10 15 20 25

Если тело внешнего цикла не будет выделено фигурными скобками, то к первому циклу будет отнесена только следующая за ним строка с функцией printf(). Только после того как функция printf() будет вызвана четыре раза подряд, начнется выполнение следующего цикла for. Во внутреннем цикле будет использовано самое последнее значение переменной iouter_val, т.е. 5, на основе которого будет сгенерирован и выведен очередной функцией printf() соответствующий ряд чисел.

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

Вот первый пример:

/*

*nsloop3.c

*

Еще одна

программа на языке С, демонстрирующая использование

фигурных

скобок

 

*

в

конструкциях со вложенными циклами.

*/

 

 

 

#include <stclio.h> int main () {

int iouter_val, iinner_val;

for(iouter_val = 1; iouter_val <= 4; iouter_val++)

{ for(iinner_val = 1; iinner_val <= 5; iinner_val++)

printf("%3d",

iouter_val * iinner_val);

}

 

return(0);

 

}

 

Запишем эту же программу несколько иначе:

/*

*nsloop4.c

*Видоизмененный вариант предыдущей программы.

*/

#include <stdio.h> int main() {

int iouter_yal, iinner_val;

for(iouter_val = 1; iouter_val <= 4; iouter_val++) for(iinner_val = 1; iinner_val <= 5; iinner_val++) printf("%3d", iouter_val * iinner_val);

return(0); }

В обоих случаях на экран будет выводиться одна и та же последовательность:

1

2

3

4

5

2

4

6

8

10

3

6

9

12

15

4

8

12

16

20

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

Цикл while

104

В языках C/C++ цикл while обычно используется в тех случаях, когда число повторений цикла заранее не известно. Он является циклом с предусловием, как и цикл for. Другими словами, программа проверяет истинность условия цикла до того, как начать следующую итерацию.

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

while(условие) выражение;

Если тело цикла состоит из нескольких строк, необходимо использовать фигурные скобки:

while(условие) ( выражение1; выражение2; выражениеЗ;

выражение-п; }

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

/*

*while.с

*В этой программе на языке С демонстрируется использование цикла while.

*/

#include <stdio.h> #define WORD 16 #define ONE_BYTE 8 int main()

{

int ivalue = 256,ibit_position = 1; unsigned int umask = 1; printf("Число%d\n", ivalue);

printf("имеет следующий двоичный эквивалент: ");

while(ibit_position <=

WORD) {

 

if((ivalue>> (WORD - ibit_position))

& umask)

/*

сдвигаем каждый

*/

printf("l");/*

бит на нулевую

*/

else

/*

позицию

и сравниваем */

printf("0");/*

число с

константой

*/

if(ibit_position == ONE_BYTE)

/* umask

*/

printf (" "); ibit_position++;

 

 

return(0);

 

 

}

 

 

Данная программа начинается с описания двух констант, WORD и ONE_BYTE, значения которых при необходимости можно модифицировать. Первая из них определяет длину в битах анализируемого числа, а вторая — позицию, после которой следует поставить пробел, чтобы отделить на экране одну группу разрядов от другой. В цикле while осуществляется поочередный (от старшего к младшему) сдвиг битов переменной ivalue в первую позицию, сравнение полученного числа со значением переменной umask (маска младшего разряда) и вывод нуля или единицы в зависимости от результата.

В следующей программе пользователю предлагается задать имена файлов для ввода и вывода данных. Цикл whilе используется для чтения данных из одного файла с одновременной записью их в другой файл, причем размер файлов изначально не известен.

/*

*fwhile.с

*В этой программе на языке С цикл while используется

*при работе с файлами. В программе демонстрируются

*дополнительные возможности файлового ввода/вывода.

*/

105

#include <stdio.h> #define MAX_CHARS 30 int main() {

int c;

FILE *ifile, *ofile;

char szi_file_name [MAX_CHARS] , szo_file_name[MAX_CHARS] ;

printf("Введите имя исходного файла: "); scanf("%s",szi_file_name);

if((ifile= fopen(szi_file_name, "r">>== NULL)

{

printf("\nФайл%s не может быть открыт", szi_file_name);

return(0);

 

 

 

printf ("Введите имя выходного файла:

");

 

scanf("%s",

szo_f ile_name) ;

 

 

if ((oflie =

fopen(szp_file_name,

"w"))

== NULL)

{

 

 

 

printf ("\nФайл %s не может быть открыт",

szo_f ile_name) ;

return (0);

 

 

 

while ((с= fgetc(ifile)) != EOF)

 

 

fputc(c,of ile) ;

 

 

return(0); }

 

 

 

В программе также показано использование функций файлового ввода-вывода данных, таких как fopen ( ) , fgetc( ) и fputc( ) (более подробно об этих функциях см. в главе "Ввод-вывод в языке С").

Цикл do/while

В цикле do/while истинность условия проверяется после выполнения очередной итерации, а не перед этим. Другими словами, тело цикла гарантированно будет выполнено хотя бы один раз. Как вы помните, циклы for и while с предусловием могут вообще остаться невыполненными, если условное выражение сразу возвратит значение false. Таким образом, цикл do/while следует использовать тогда, когда некоторое действие в программе необходимо выполнить в любом случае, по крайней мере один раз.

Цикл do/while имеет следующий синтаксис:

do .

выражение; while(условие) ;

Если тело цикла состоит более чем из одной строки, необходимо ставить фигурные скобки:

do{

выражение1; выражение2; выражениеЗ; выражение-n ; }

while(условие);

В следующем примере цикл do/while используется для получения от пользователя строки текста:

//

//dowhile.cpp

//В этой программе на языке C++ демонстрируется

//использование цикла do/while.

//

#include <iostream.h> #define LENGTH 80 int main()

{

char cSentence [LENGTH] ;

106

int iNumChars = 0, iNumWords = 1; do{

cout << "Введите предложение : ";

cin.getline (cSentence, LENGTH); } while (cSentence [0]== '\0'); while (cSentence [iNumChars] != '\0')

{ if (cSentence [iNumChars] !=''&& cSentence [iNumChars] != '\t'&&

(cSentence [iNumChars+1] == ' ' || cSentence [iNumChars+1] == '\t'|| cSentence [iNumChars+1] == '\0'))

iNumWords++;

iNumChars++;

cout<< "Вы ввели " << iNumChars<< " символов\n"; cout<< "Вы ввели " << iNumWords<< " слов"; return(0); }

В цикле do/while запрос будет повторяться до тех пор, пока пользователь не введет хотя бы один символ. При простом нажатии клавиши [Enter] функция getline( ) возвращает символ null, в таком случае цикл повторяется. Как только в массив будет записана строка, цикл завершится и программа произведет подсчет количества введенных символов и слов.

Инструкции перехода

В языках C/C++ имеется четыре инструкции перехода: goto, break, continue и return. Инструкция goto(или ее аналог) существует во многих языках высокого уровня и предназначена для принудительного перехода по указанному адресу, определяемому меткой. Ее синтаксис таков:

goto метка;

В отличие от языка типа Basic, где данная инструкция находит широкое применение, в C/C++ наличие в программе команды goto рассматривается как плохой стиль программирования, и считается, что в четко структурированной и грамотно написанной программе этой инструкции быть не должно.

Инструкция break

Инструкция break позволяет выходить из цикла еще до того, как условие цикла станет ложным. По своему действию она напоминает команду goto, только в данном случае не указывается точный адрес перехода: управление передается первой строке, следующей за телом цикла. Рассмотрим пример:

/*

*break. с

*В этой программе на языке С демонстрируется использование

*инструкции break.

*/

int main ()

{ int itimes = 1, isum = 0; while (itimes < 10) {

isum += itimes; if (isum > 20) break; itimes++; return (0); }

Проанализируйте работу этой программы с помощью отладчика, контролируя значения переменных isum и itimes. Обратите внимание на то, что происходит, когда переменная isum достигает значения 21. Вы увидите, что в этом случае выполняется инструкция break, в результате чего цикл прекращается и выполняется первая строка, следующая за телом цикла. В нашем примере это инструкция return, которая завершает программу.

107

Инструкция continue

Инструкция continue заставляет программу пропустить все оставшиеся строки цикла, но сам цикл не завершается. Действие этой инструкции аналогично выполнению команды goto, указывающей на строку условия цикла. Если условное выражение возвратит true, цикл будет продолжен.

Ниже показан текст программы, реализующей игру в угадывание чисел и использующей возможности инструкции continue:

/*

*continue.с

*В этой программе на языке С демонстрируется использование

*инструкции continue.

*/

#include <stdio.h> #define TRUE 1 #define FALSE 0 int main ()

{

int ilucky_number = 77, iinput_val, inumber_of_tries = 0, iam_lucky = FALSE; while(!iam_lucky) { printf("Введите число: "); scanf("%d",&iinput_val); inumber_of_tries++;

if(iinput_val == ilucky_number) iam_lucky = TRUE; else { if(iinput_val > ilucky_number) printf("Ваше число больше!\n"); else

printf("Ваше число меньше!\n"); continue; } printf("Вам потребовалось всего %d попыток, чтобы отгадать счастливое число!", inumber_of_tries); }

return(0); }

В цикле while пользователю предлагается ввести свой вариант числа, после него значение переменной inumber_of_tries, хранящей число попыток, увеличивается на единицу. Если попытка оказалась неудачной, программа переходит в ветвь else, в которой пользователю дается подсказка и выполняется инструкция continue, подавляющая вывод поздравительного сообщения функцией printf(). Тем не менее, выполнение цикла продолжается. Как только будет получено соответствие введенного и счастливого чисел, переменной iam_lucky будет присвоено значение true, в результате чего будет выполнена функция printf( ) .

Совместное использование инструкций break и continue

Для решения некоторых, , задач удобно комбинировать инструкции break и continue. Рассмотрим следующую программу на языке С:

/*

*breakcon.c

*В этой программе на языке С используются инструкции break и continue.

*/

#include <stdio.h> #include <ctype.h> #define NEWLINE '\n' int main()

{

108

int c;

while((c=getchar()) != EOF) { if(isascii(с) == 0) {

printf("Введенный символ не является ASCII-символом; ") ; printf("продолжение невозможно\n");

break;

if(ispunct(c) II isspace(c)) { putchar(NEWLINE);

continue;

}

if(isprint(c) == 0) continue;

putchar(c); } return(0);

}

На вход программы поступают такие данные:

word control < exclamation! apostrophe' period. ^Z

Вот что будет получено в результате: word control

exclamation apostrophe period

Данная программа считывает поступающие символы до тех пор, пока не будет введен признак конца файла ^Z [Ctrl+Z]. Затем производится анализ введенных символов, удаляются непечатаемые знаки, а все слова разделяются разрывами строк. Все эти действия выполняются с помощью функций, описанных в файле CTYPE.H: isascii(), ispunct(),isspace() и isprint(}.Каждая функция получает в качестве аргумента символ и возвращает ноль или единицу в зависимости от принадлежности этого символа соответствующей категории.

Функция isascii() проверяет, является ли символ обычным ASCII-символом (т.е. его код находится в диапазоне 0—127), функция ispunct() — является ли символ знаком препинания, функция isspace() — является ли символ пробельным, а функция isprint() — является ли символ печатаемым. С помощью этих функций программа определяет, следует ли продолжать выполнение, а если продолжать, то как поступать с каждым из введенных символов.

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

Если формат входных данных подходящий, то проверяется, является ли введенный символ пробелом или знаком препинания. Если это так, выводится пустая строка и выполняется инструкция continue, инициирующая следующую итерацию цикла.

Далее проверяется, является ли введенный символ печатаемым. Обратите внимание, что во входных данных содержится символ < ([Ctri+Q]). Поскольку это непечатаемый символ, он не отображается вовсе, и выполняется инструкция continue, завершающая текущую итерацию цикла.

В случае, если анализируемый символ является текстовым, выполняется функция putchar(), выводящая его на экран.

Инструкция return

Иногда необходимо прервать выполнение программы задолго до Того, как будут выполнены все ее строки. Для этой цели в языках C/C++ существует уже знакомая вам инструкция return, которая завершает выполнение той функции, в которой она была вызвана. Если вызов произошел в функции main() , то завершается сама программа. В этом случае инструкция return принимает единственный целочисленный аргумент, называемый кодом завершения. В

109

операционных системах UNIX и MS-DOS нулевой код воспринимается как нормальное завершение программы, тогда как любое другое значение является признаком ошибки.

Код завершения программы может проверяться вызывающими ее процессами. Например, если программа была запущена из командной строки и код ее завершения показал наличие какой-то ошибки, операционная система может выдать предупреждающее сообщение. Помимо завершения работы программы инструкция return вызывает принудительный вывод всех содержащихся в буфере данных и закрытие всех открытых программой файлов.

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

//

//return.cpp

//В этой программе на языке C++ демонстрируется использование

//инструкции return.

//

#include <iostream.h> #define LIMIT 30

int main() {

int irow, irequested_qty, iscores[LIMIT], imin_score, imax_score; float fsum = 0, faverage;

cout<< "\nВведите число значений ряда: "; cin >> irequested_qty;

if(irequested_qty > LIMIT) {

cout<< "\nВы можете ввести не более " << LIMIT << " значений.\n" cout<< "\n>>> Программа завершена. <<<\n";

return(0);

}.

for(irow = 0; irow < irequested_qty; irow++) {

cout << "\nВведите "'<<irow+1 << "-иэлементряда: cin >> iscores[irow];

}

for(irow = 0; irow < irequested_qty; irow++) fsum = fsum + iscores[irow];

faverage = fsum/(float)irequested_qty; imax^score = imin_score = iscores[0];

for(irow =1;irow < irequested_qty; irow++) {

 

 

if(iscores[irow] > imax_score)

 

 

 

 

 

imax_score = iscores[irow];

 

 

 

 

 

if(iscores[irow] < imin_score)

 

 

 

 

 

imin_score = iscores[irow];

 

 

 

 

 

}

"\nМаксимальное значение

=

"

<<

imax_score;

cout<<

cout<<

"\nМинимальное значение

 

=

"

<<

imin_score;

cout<<

"\nСреднее значение

=

"

<<

faverage;

return(0); }

Функция exit( )

Существует библиотечная функция exit(),которая аналогична инструкции return и объявлена в файле STDLIB.H. В этом файле также описаны две дополнительные константы, которые могут быть переданы в качестве аргументов этой функции: exit_success(сигнализирует об успешном завершении программы) и exit_failure(сигнализирует об ошибке). Использование этих констант позволяет сделать текст программы чуть более понятным, хотя компилятор выдает предупреждение, если не встречает в функции main() ни одной инструкции return.

Рассмотрим слегка видоизмененный вариант предыдущей программы.

110

Соседние файлы в предмете Программирование на C++