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

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

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

Любая программа, написанная профессиональным программистом, всегда начинается с комментариев. В языке С блок комментариев Начинается символами / *, а заканчивается символами */. Все, что находится между ними, игнорируется компилятором.

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

#include <stdio.h>

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

Вслед за директивой препроцессора расположен блок описания функции:

int main ()

return(0); /* или return 0; */

Все программы на языке С обязательно содержат функцию main ( ) . С нее начинается выполнение программы, которое завершается вызовом инструкции return. Ключевое слово intслева от имени функции указывает на тип возвращаемых ею значений. В нашем случае возвращается целое число. Значение 0 в инструкции return будет воспринято как признак успешного завершения программы. Допускается использование инструкции return без круглых скобок.

Тело функции main () расположено между символами { и } , называемыми фигурными скобками. Фигурные скобки широко применяются для выделения в программе блоков инструкций. Это может быть тело функции, как в данном примере, тело цикла, например for или while, либо операторная часть условных конструкций if/else или switch/case.

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

printf("Привет, юзер!");

Прототип функции printf () описан в файле STDIO.H.

Простейшая программа на языке C++

В следующем примере мы реализуем те же самые действия, но на этот раз средствами языка

C++.

//

//simple.cpp

//Ваша первая программа на C++ #include <iostream.h>

int main ()

{

cout << " Здравствуй, мир! "; return(0);

}

Имеется три различия между этой программой и той, что мы рассмотрели ранее. Во-первых, комментарии выделены не парой символов /* */, а символами //, расположенными в каждой строке блока комментариев. Во-вторых, имя файла в директиве finclude было изменено на IOSTREAM.H. И наконец, вывод дайных осуществляется посредством объекта cout, который появился в программе "благодаря" файлу IOSTREAM.H. В следующих примерах книги мы будем обращать ваше внимание на другие отличия языка C++ от С.

Получение данных от пользователя в языке С

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

/*

*ui.c

61

*Данная программа предлагает пользователю ввести длину в футах, после

*чего переводит полученное значение в метры и сантиметры.

*/

#include <stdio.h> int main ()

{

float feet, meters, centimeters; printf("Введите количество футов: ") ; scanf("%f,Sfeet);

while(feet > 0) {

centimeters = feet * 12 * 2.54;

meters = centimeters/100; printf("%8.2f(футы) равняется\n", feet);

printf("%8.2f(метры) \n",meters); printf("%8.2f(сантиметры) \n",centimeters); printf("\nВведите другое значение \n"); printf("(О- конец программы): ") ; scanf("%f", &feet);

}

printf(">>>До свидания! <<<") ; return(0);

}

Объявление переменных

Первое, что бросается в глаза в этом примере, — объявление переменных: float feet, meters, centimeters;

В языке С все переменные должны быть объявлены до того, как на них будет осуществлена ссылка где-либо в программе. Ключевое слово float перед именами переменных говорит о том, что им назначается стандартный тип данных языка С — действительное число с плавающей запятой одинарной точности.

Ввод данных пользователем

Следующие строки, вид которых может показаться довольно необычным, обеспечивают ввод данных пользователем:

printf("Введите количество футов: "); scanf("%f",&feet);

Функция scant () должна содержать строку форматирования, которая определяет, в каком порядке будут вводиться внешние данные и как они будут интерпретироваться программой. Заключенный в кавычки параметр %f указывает, что вводимые данные будут приведены к типу float. В языках С и C++ для значений этого типа отводится 4 байта. (Более подробно о различных типах данных, существующих в C/C++, см. в следующей главе.)

Оператор взятия адреса

Обратите внимание, что.в рассмотренном выше примере переменной feet в функции scanf () предшествует символ амперсанда (&). Это оператор взятия адреса. Всюду, где имени переменной предшествует этот оператор, компилятор будет использовать вместо значения переменной ее адрес. Особенность функции scanf () заключается в том, что она ожидает именно адрес переменной, которой будет присвоено новое значение.

Простейший цикл while

Один из самых простых способов создания цикла в программе на языке С заключается в использовании инструкции while:

while(feet > 0)

62

{

...

}

Это так называемый цикле предусловием. Он начинается с ключевого слова whilе, за которым следует логическое выражение, возвращающее TRUE или FALSE. Фигурные скобки необходимы, когда цикл содержит более одной команды. В противном случае скобки необязательны. Строки, заключенные между фигурными скобками, формируют тело цикла.

Старайтесь придерживаться общепринятого стиля оформления циклов и условных конструкций наподобие if /else. Хотя для компилятора не имеет значения наличие символов пробела, табуляции и пустых строк (в процессе компиляции они все равно будут отброшены), следует помнить о некоторых общих правилах форматирования текста программы, чтобы сделать ее удобочитаемой для других. Так, при выделении тела цикла с предусловием открывающая фигурная скобка ставится после закрывающей круглой скобки условного выражения, в той же строке, а закрывающая скобка — после всех инструкций цикла в отдельной строке, причем с тем же отступом, что и первая строка цикла.

Вывод данных на экран

В рассматриваемом примере мы повстречались с более сложным способом вывода информации на экран:

printf("%8.2f(футы) равняется\n",feet); printf("%8.2f(метры) \n", meters); printf("%8.2f(сантиметры) \n",centimeters); printf("\nВведите другое значение' \n"); printf("(О— конец программы): ");

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

Давайте рассмотрим элементы строки форматирования первой из функций printf ().

Элемент строки Назначение форматирования

%8.2f

Задает интерпретацию переменной feet как числа типа float в

следующем формате: 8 символов до запятой и 2 символа после

 

(футы) равняется После вывода значения переменной feet будет сделан пробел и отображена строка (футы) равняется

\n

Символ новой строки

 

 

,

Запятая отделяет строку форматирования от списка обозначенных в ней переменных

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

Введите количество футов: 10 10.00 (футы) равняется

3.05(метры)

304.80 (сантиметры)

Введите другое значение (0 — конец программы): 0

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

Таблица 4.2. Управляющие последовательности

Последовательность

Что обозначает

Предупреждающий звуковой сигнал

\b

Стирание предыдущего символа

63

\f

Перевод страницы

\n

Новая строка

\r

Возврат каретки

\t

Горизонтальная табуляция

\v

Вертикальная табуляция

\?

Знак вопроса

\'

Одинарная кавычка

\"

Двойная кавычка

\\

Обратная косая черта

\ddd

ASCII-код символа в восьмеричной системе

\xdd

ASCII-код символа в шестнадцатеричной системе

Получение данных от пользователя в языке C++

Ниже показана версия предыдущего примера, переписанная в соответствии с синтаксисом языка C++:

//

//ui.cpp

//Данная программа предлагает пользователю ввести длину в футах, после //чего переводит полученное значение в метры и сантиметры.

//

#include <iostream.h> #include <iomanip.h> int main()

float feet, meters, centimeters;

cout << "Введите количество футов: "; cin >> feet;

while(feet > 0)

{

centimeters = feet * 12 * 2.54; meters = centimeters/100;

cout << setw(8) << setprecision(2)

<<setiosflags(ios: : fixed) << feet

<<" (футы) равняется \n"; cout << setw(8)

<<meters << " (метры) \n"; cout << setw(8)

<<centimeters << " (сантиметры) \n";

cout << "\nВведитедругоезначение\n"; cout << "(0— конец программы): "; cin >> feet;

}

cout << ">>> До свидания! <<<";

return(0);

Можно обнаружить пять основных различий между показанной программой на языке C++ и ее аналогом на С. Первые два состоят в применении объектов cin и cout вместо функций scanf () и printf (). В выражениях с ними также используются операторы << (для вывода) и >> (для ввода) классов ostream и istream, подключаемых в файле IOSTREAM. Н. Оба этих оператора являются перегруженными и поддерживают ввод/вывод данных всех базовых типов. Их можно также перегрузить для работы с пользовательскими типами данных.

Оставшиеся три различия связаны с особенностями форматированного вывода в C++. Чтобы добиться такого же формата вывода, какой был получен с помощью простой строки форматирования %8. 2f в программе на языке С, в C++ потребуются три дополнительных выражения. Файл IOMANIP.H, подключаемый в начале программы, содержит объявления трех функций, являющихся членами класса ios (базовый в иерархии классов ввода/вывода): setw(),setprecision () и setios-flags (). Функция setw () задает минимальную ширину (в символах)

выводимого поля. Функция setprecision () задает число цифр после десятичной точки при выводе чисел с плавающей запятой. Функция setw () вынуждена повторяться три раза, поскольку определяет формат вывода только следующей за ней переменной, после чего все сделанные установки сбрасываются. В отличие от нее функция setiosflags () вызывается один

64

раз, устанавливая флаг fixed, который задает вывод чисел с плавающей запятой в фиксированном формате, т.е. без экспоненты. Те программисты, которые работают с языком C++, но хотят использовать привычную функцию printf (), могут подключить библиотеку

STDIO.H.

Файловый ввод-вывод

Часто требуется вводить данные не с клавиатуры, а из файла и не выводить полученный результат на экран, а записывать его в файл. Ниже показан простейший пример того, как организовать в программе работу с файлами:

/*

*filel.c

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

для

*ввода, так и для вывода данных. Программа читает значение переменной

*forder_price из файла customer.dat, вычисляет значение переменной

*fbilling_price и записывает его в файл billing.dat.

*/

#include <stdio.h> #define MIN_DISCOUNT .97 #define MAX_DISCOUNT .95

int main ()

{

float forder_price, fbilling_price; FILE *fin,*fout;

fin = fopen("customer.dat","r"); fout = fopen("billing.dat","w"); while (fscanf(fin,"%f",&forder_price) != EOF) { fprintf(fout,"Для заказа на сумму \t$%8.2f\n",

forder_price); if (forder_price < 10000) fbilling_price = forder_price * MIN_DISCOUNT;

else fbilling_price = forder_price * MAX_DISCODNT; fprintf(fout,"цена со скидкой равна \t$%8.2f\n\n", fbilling_price);

}

return(0);

}

Каждому файлу в программе соответствует свой указатель типа file. Структура file, описанная в библиотеке STDIO.H, содержит всевозможную информацию о файле, включая путь к нему, имя и атрибуты. В приводимом ниже выражении создаются два указателя файла:

FILE *fin, *fout;

В следующих двух строках файлы открываются для чтения и записи соответственно: fin = fopen ("customer.dat","r"); fout = fopen("billing.dat","w");

Каждая функция fopen () возвращает инициализированный указатель файла. В процессе выполнения программы их значения не должны меняться вручную.

Второй параметр функции fopen (} определяет режим доступа к файлу (табл. 4.3). Файл может быть также открыт в следующих режимах: текстовом (включается путем добавления символа t к обозначению режима доступа) и двоичном (включается путем добавления символа Ь). В текстовом режиме компилятор языка С в процессе ввода данных заменяет пары символов возврата каретки и перевода строки одним символом новой строки. При выводе выполняется обратное преобразование. В двоичных файлах эти символы никак не обрабатываются.

Таблица 4.3. Режимы доступа к файлу в языке С

Режим доступа Описание

аФайл открывается для добавления данных; если файл не существует, он создается; все новые данные добавляются в конец файла

а+

Аналогичен предыдущему режиму, но допускает считывание данных

65

rОткрывает файл только для чтения; если файл не существует, открытия файла не происходит

r+

Открывает файл как для чтения, так и для записи; если файл не

существует, открытия файла не происходит

 

 

 

w

Открывает пустой файл для записи; если файл существует, его содержимое стирается

 

 

w+

Открывает пустой файл как для записи, так и для чтения; если файл

существует, его содержимое стирается

 

Режимы r+, w+ и а+ позволяют как читать данные из файла, так и осуществлять их запись. При переходе от считывания к записи не забудьте модифицировать текущую позицию указателя файла с помощью функций fsetpos (), fseek()или rewind() .

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

/*

*filel.c

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

для

*ввода, так и для вывода данных. Программа читает значение переменной

*forder_price из файла customer.dat, вычисляет значение переменной

*fbilling_price и записывает его в файл billing.dat.

*/

#include <stdio.h> #define MIN_DISCOUNT .97 #define MAX_DISCOUNT .95 int main() {

float forder_price, fbilling_price; FILE *fin,*fout;

fin = fopen ("customer.dat","r"); fout = fopen("billing.dat","w"); while (fscanf (fin,"%f",&forder_price) != EOF)

{ fprintf(fout,"Для заказа на сумму \t$%8.2f\n", forder_price); if (forder_price < 10000) fbilling_price = forder_price * MIN_DISCOUNT;

else fbilling_price = forderjirice * MAX_DISCOUNT; fprintf(fout,"цена со скидкой равна \t$%8.2f\n\n", fbilling_price);}

fclose(fin); fclose(fout) ; return(0);}

Следующая программа, написанная на языке C++, выполняет те же функции, что и рассмотренная нами программа на языке С.

//

//file2.cpp

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

//

ввода, так

и для вывода данных.

Программа

читает

значение

переменной

из файла customer.dat,

вычисляет

значение

//

forder_price

переменной

// fbilling_price и записывает его в файл billing.dat.

//

#include <fstream.h> #include <iomanip.h> #define MIN_DISCOUNT .97 #define MAX DISCOUNT .95

66

int main( ) {

float forder_price, fbilling_price; ifstream fin("customer.dat"); ofstream fout("billing.dat");

fin >> forder_price; while (Ifin.eofO){

fout << setiosflags(ios::fixed); fout << "Для заказа на сумму\t\t$" << setprecision(2)

<< setw(8)<< forder_price << "\n"; if (forder_price < 10000)

fbilling_price = forder_price * MIN_DISCOUNT; else fbilling_price = forder_price * MAXDISCOUNT;

fout << "цена со скидкой равна\t$"

<< setw(8) << fbilling_price << "\n\n"; fin >> forder_price; fin. close () ;

fout .close () ; return(0);

Операции записи данных в файл и считывания информации из файла отличаются в языках C++ и С. Как видно из сравнения двух примеров, вместо вызова функции fopen () происходит создание двух объектов классов ifstream (содержит функции файлового ввода) и ofstream (содержит функции файлового вывода). Далее работа выполняется с помощью уже знакомых нам операторов >> и <<, а также функций форматирования setw(),setprecision () и setiosflags(). В целом в C++ для ввода/вывода данных посредством консолей и файлов используются те же операторы с тем же синтаксисом, что существенно упрощает программирование операций ввода/вывода — область программирования, всегда считавшаяся сложной и чреватой ошибками.

67

Глава 5. Работа с данными

Идентификаторы

Ключевые слова

Стандартные типы данных

o

Символы

o

Три типа целых чисел

o Модификаторы signed и unsigned o Числа с плавающей запятой

o Перечисления

oНовый тип данных языка С++ - bool

Квалификаторы

oКвалификатор const

o Директива #define

o Квалификатор volatile

oОдновременное применение квалификаторов const и volatile

Преобразование типов данных

oЯвное преобразование типов

Классы памяти

oОбъявление переменных на внешнем уровне

o Объявление переменных на внутреннем уровне

o Правила определения области видимости переменных

oОбъявление функций

Операторы

oПобитовые операторы

o Операторы сдвига

o Инкрементирование и декрементирование o Арифметические операторы

o Оператор присваивания

o Комбинированные операторы присваивания o Операторы сравнения и логические операторы o Условный оператор

o Оператор запятая

68

Приоритеты выполнения операторов

Есть одно справедливое утверждение: "Вы не сможете называть себя профессиональным программистом на C/C++ до тех пор, пока не прекратите мыслить на любых других языках и переводить свои мысли на C/C++". Вы можете разбираться в языках COBOL, FORTRAN, Pascal или PL/I и, зная хотя бы один из этих языков, заставить себя изучить другие языки из этого списка, чтобы успешно программировать на любом из них. Но такой подход может не сработать в случае изучения языков С и C++. Дело в том, что они достаточно сильно отличаются от других языков как по используемым средствам программирования, так и по уникальной логике поиска решений. Если вы не измените свой стиль мышления при написании программ, то не сможете реализовать все возможности и преимущества C/C++. И, что хуже, вы даже не сможете разобраться в логике программ, написанных настоящими специалистами. Техника написания программ на языках C/C++ изобилует таким количеством нюансов, что беглого взгляда на программу достаточно, чтобы оценить профессиональный уровень программиста!

С этой главы мы начнем детальное изучение структуры языков C/C++. Прежде всего следует познакомиться со стандартными типами данных и операторами, с помощью которых можно манипулировать данными.

Идентификаторы

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

Идентификатор представляет собой последовательность символов произвольной длины, содержащую буквы, цифры и символы подчеркивания, но начинающуюся обязательно с буквы или символа подчеркивания. Компилятор распознает только первые 31 символ. (Учтите, что другие программы, принимающее данные от компилятора, например компоновщик, могут распознавать последовательности даже еще меньшей длины.)

Языки С и C++ чувствительны к регистру букв. Другими словами, компилятор распознает прописные и строчные буквы как разные символы. Так, переменные NAME_LENGTH и Name_Length будут рассматриваться как два разных идентификатора, представляющих различные ячейки памяти. То есть вы можете создавать идентификаторы, одинаково читаемые, но отличающиеся написанием одной или нескольких букв.

Использование как прописных, так и строчных букв в идентификаторах позволяет сделать программный код более читабельным. Например, идентификаторы, которые объявлены в файлах заголовков, включаемых в программу с помощью директив #include, часто записывают прописными буквами, чтобы они бросались в глаза. В результате, где бы вы ни встретили идентификаторы, записанные прописными буквами, сразу станет ясно, где они описаны.

Хотя допускается использование символа подчеркивания в начале имени идентификатора, мы не рекомендуем так поступать, поскольку данный способ записи применяется в именах встроенных системных подпрограмм и переменных. Совпадение имени идентификатора с зарезервированным именем вызовет конфликт в работе программы. Два символа подчеркивания (_) в начале имени идентификатора применяются в стандартных библиотеках языка C++.

Среди программистов на С принято негласное соглашение начинать любое имя с префикса типа данных этого идентификатора. Например, все целочисленные идентификаторы должны начинаться буквой i (integer), идентификаторы с плавающей запятой — буквой f (float), строки, завершающиеся нулевым символом, — буквами sz (stringzero), указатели — буквой р (pointer) и т.д. Зная об этих соглашениях, вы, бросив лишь беглый взгляд на текст программы, сможете сразу определить не только идентификаторы, используемые в этой программе, но и их типы данных. Это существенно упрощает восприятие программных текстов.

Ниже показаны примеры идентификаторов:

i itotal frangel

szfirst_name Ifrequency

69

imax iMax iMAX NULL EOF

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

lst_year #social_security Not Done!

Первое имя недопустимо, поскольку начинается с цифры. Второе имя начинается с символа #, а третье — содержит недопустимый символ в конце имени. Посмотрите теперь на следующие идентификаторы и попробуйте определить, допустимы ли они:

o oo ooo

Как это ни покажется странным, все четыре имени допустимы. В первых трех используется буква о в верхнем регистре. Поскольку длина идентификаторов разная, никаких конфликтов не происходит. Имя четвертого идентификатора состоит из пяти символов подчеркивания (_). Но достаточно ли содержательны эти имена? Определенно нет, хотя они вполне допустимы. Таким образом, программист должен позаботиться о том, чтобы все имена функций, констант, переменных и другие идентификаторы несли какой-то смысл.

Обратите также внимание, что, поскольку строчные и прописные буквы различимы, следующие три идентификатора уникальны:

MAX_RATIO max_ratio Max_Ratio

Чувствительность компилятора языка С к регистру букв может вызвать головную боль у начинающих программистов. Например, если вместо printf () в программе будет записано Printf(),то компилятор выдаст сообщение об ошибке вида "unknown identifier" (неизвестный идентификатор). На языке Pascal можно использовать любое написание имен, например: writeln, WRITELN или writeLn.

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

printf("%D",integer_value);

Предположив, что переменная integer_value записана правильно, вы можете не заподозрить ошибки. Тем не менее, ошибка есть. Формат вывода может задаваться в языке С только оператором %d, но не %D.

И последнее замечание касательно идентификаторов: имя идентификатора не должно совпадать (с учетом регистра) с именем ключевого слова.

Ключевые слова

Ключевые слова являются встроенными идентификаторами, каждому из которых соответствует определенное действие. Изменить назначение ключевого слова нельзя. (С помощью директивы препроцессора #define можно создать "псевдоним" ключевого слова, который будет дублировать его действия, возможно, с некоторыми изменениями.) Помните, что имена идентификаторов, создаваемых в программе, не могут совпадать с ключевыми словами языков C/C++ (табл. 5.1).

Таблица 5.1. Ключевые слова языков С/С++ (начинающиеся с символов подчеркивания специфичны для компилятора Microsoft)

asm

else

main

struct

 

 

 

 

70

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