Паппас К., Мюррей У. - Visual C++ 6. Руководство разработчика - 2000
.pdfЛюбая программа, написанная профессиональным программистом, всегда начинается с комментариев. В языке С блок комментариев Начинается символами / *, а заканчивается символами */. Все, что находится между ними, игнорируется компилятором.
Следующая строка, называемая директивой препроцессора, характерна для языка С.
#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
- #13.08.201334.52 Mб91Липман С., Лажойе Ж., Му Б. - Язык программирования C++. Вводный курс - 2007.djvu
- #13.08.201347.18 Mб127Литвиненко Н.А. - Технология программирования на C++. Win32 API-приложения - 2010.djvu
- #
- #
- #13.08.201317.53 Mб103Оберг Р., Торстейсон П. - Архитектура .NET и программирование на Visual C++ - 2002.pdf
- #
- #
- #
- #
- #
- #