- •Издано в рамках Инновационной образовательной программы ннгу: Образовательно-научный центр «Информационно-телекоммуникационные системы: физические основы и математическое обеспечение»
- •Глава 1. Основные понятия 13
- •Глава 3. Работа с числовыми данными 42
- •Глава 4. Операторы. Ключевые слова 52
- •Глава 5. Управление и циклы 64
- •Глава 6. Массивы 77
- •Глава 7. Функции 84
- •Глава 8. Символы и строки 102
- •Глава 9. Препроцессор 113
- •Глава 10. Указатели и ссылки 119
- •Глава 11. О файлах и командной строке 133
- •Глава 12. Работа с экраном дисплея 145
- •Глава 13. Внутреннее представление чисел 157
- •Глава 14. Структуры, перечисления, объединения 179
- •Глава 15. Классы 204
- •Глава 16. Программы из нескольких файлов 233
- •Глава 21. Шаблоны, исключения 321
- •Предисловие
- •Глава 1.Основные понятия
- •1.1.Элементы языка программирования
- •Алфавит
- •Лексемы
- •Выражения
- •Функции
- •Комментарии
- •1.2.Процесс создания программы
- •1.3.Первая программа Программа 1. Приветствие
- •1.4.Состав программы
- •Загрузка
- •Работа с окнами
- •Настройка среды
- •Указание каталогов библиотек
- •Подключение графической библиотеки
- •Назначение текущего каталога
- •Работа с блоками текста в редакторе
- •Выполнение программы
- •Отладка программ
- •Программа 2. Деление чисел
- •Синтаксические ошибки
- •Ошибки в процессе работы программы
- •Трассировка программ
- •Просмотр текущих значений выражений
- •Разработка консольных приложений
- •Программа 3. Hello
- •Выполнение и отладка программы
- •Файлы проекта
- •Автоматическая генерация кода
- •Особенности ввода и вывода
- •Глава 3.Работа с числовыми данными
- •3.1.Целые типы
- •Целые константы
- •Программа 4. Операции над целыми
- •3.2.Числа с плавающей точкой
- •Плавающие константы
- •3.3.Ввод и вывод чисел
- •Программа 5. Точность плавающих чисел
- •3.4.Логический тип и логические операции
- •3.5.Математические функции
- •Глава 4.Операторы. Ключевые слова
- •4.1.Операторы
- •Унарные операторы
- •Бинарные операторы
- •Оператор запятая
- •Условное выражение
- •Операторы присваивания
- •4.2.Приоритеты операторов
- •4.3.Ключевые слова
- •Продолжение таблицы 23. Ключевые слова стандарта языка Cи
- •4.4.Структура программы
- •Объявления переменных
- •Объявления и определения
- •Инструкции и блоки
- •4.5.Константы
- •Задачи 1-17 . Простейшие вычисления
- •Глава 5.Управление и циклы
- •5.1.Условный оператор
- •Программа 6. Максимальное из двух чисел
- •5.2.Операторы цикла
- •Цикл с предусловием while
- •Программа 7. Суммирование цифр целого
- •Цикл for
- •Программа 8. Поиск максимума и минимума
- •Цикл do-while
- •Программа 9. Вычисление квадратного корня
- •5.3.Переключатель
- •Программа 10. День недели
- •5.4.Операторы break и continue
- •Программа 11. Сумма положительных чисел
- •Задачи 18-52. Выбор и циклы
- •Глава 6.Массивы
- •6.1.Одномерные массивы
- •Программа 12. Проверка упорядоченности массива
- •6.2.Двумерные массивы
- •Программа 13. Подсчет выручки
- •Задачи 53-69. Одно- и двумерные массивы
- •Глава 7.Функции
- •7.1.Определение функции
- •7.2.Формальные параметры и фактические аргументы
- •Пpограмма.14. Степени целых чисел
- •7.3.Автоматические и статические переменные
- •Программа 15. Автоматические и статические переменные
- •7.4.Прототипы функций
- •7.5.Массивы как аргументы функций
- •7.6.Внешние переменные
- •Программа 16. Сортировка массива
- •7.7.Рекурсия
- •Программа 17. Рекурсивная печать целого
- •7.8.Перегруженные имена функций
- •Программа 18. Перегрузка функций
- •7.9.Аргументы функций по умолчанию
- •Программа 19. Аргументы по умолчанию
- •Задачи 70-96. Функции
- •Глава 8.Символы и строки
- •8.1.Символы
- •Символьные константы
- •Программа 20. Представления символов
- •Ввод и вывод символов
- •Программа 22. Печать текста по словам
- •8.2.Строки символов
- •Строковые константы
- •Ввод и вывод строк
- •Средства работы со строками
- •Программа 23. Реверсирование строк
- •Задачи 97-121. Символы и строки
- •Глава 9.Препроцессор
- •9.1.Директивы препроцессора
- •9.2.Макросы
- •Программа 24. Возможности препроцессора
- •Задачи 122-124. Макросы
- •Глава 10.Указатели и ссылки
- •10.1.Указатели и адреса
- •Программа 25. Расчет треугольника
- •10.2.Указатели и массивы
- •10.3.Адресная арифметика
- •10.4.Символьные указатели
- •10.5.Массивы указателей
- •Программа 26. Названия месяцев
- •10.6.Указатели на функции
- •Программа 27. Поиск максимума функции
- •10.7.Ссылки
- •Программа 28. Использование ссылок
- •10.8.Операторы new и delete
- •Программа 29. Выделение и освобождение памяти
- •Задачи 125-134. Указатели и ссылки
- •Глава 11.О файлах и командной строке
- •11.1.Знакомство с файлами
- •Программа 30. Копирование файлов
- •11.2.Командная строка
- •11.3.Перенаправление стандартного ввода и вывода на файл
- •11.4.Аргументы командной строки
- •Программа 31. Эхо аргументов командной строки
- •Программа 32. Печать строк, содержащих образец
- •Задачи 135-147. Файлы и командная строка
- •Глава 12.Работа с экраном дисплея
- •12.1.Текстовый режим
- •Программа 33. Российский флаг
- •12.2.Графический режим
- •Графические драйверы и режимы
- •Инициализация графики
- •Функции рисования
- •Программа 34. Звезда
- •Задачи 148-158. Работа с экраном
- •Глава 13.Внутреннее представление чисел
- •13.1.Двоичная система счисления
- •13.2.Беззнаковые целые
- •13.3.Двоичный дополнительный код
- •13.4.Двоичный код с избытком
- •13.5.Побитовые операторы
- •Программа 35. Побитовые операторы
- •13.6.Дробные числа в двоичной системе
- •13.7. Внутреннее представление плавающих типов
- •13.8.Преобразование типов
- •Значения логических выражений
- •Арифметические преобразования
- •Преобразование при присваивании
- •Явное приведение типа
- •Задачи 159-166. Побитовые операторы
- •Глава 14.Структуры, перечисления, объединения
- •14.1.Объявление структур
- •14.2.Структуры и функции
- •14.3.Указатели на структуры
- •Программа 36. Точки и прямоугольники на экране
- •14.4.Массивы структур
- •Программа 37. Подсчет ключевых слов
- •14.5.Перечисления
- •Программа 38. Использование перечислений
- •14.6. Объединения
- •Программа 39. Внутреннее представление float
- •14.7.Битовые поля
- •14.8.О бинарных файлах
- •Программа 40. Анализ успеваемости
- •Задачи 167-174. Структуры
- •Глава 15.Классы
- •Программа 41. Время как структура
- •15.2.Встроенные функции
- •15.3.Классы. Скрытие данных
- •Программа 42. Класс дат
- •15.4.Конструкторы
- •Программа 43. Конструкторы в классе дат
- •15.5.Статические члены класса
- •Программа 44. Размер класса и объектов класса
- •15.6.Друзья класса
- •Программа 45. Статические члены и друзья класса
- •15.7.Копирование объектов класса
- •Программа 46. Копирование объектов
- •15.8.Управление доступом
- •Структуры и классы
- •Правила доступа
- •15.9.Ссылка на себя
- •Программа 47. Модификация дат
- •15.10.Деструкторы
- •Программа 48. Деструктор в классе дат
- •Программа 49. Многоугольники
- •Задачи 175-185. Работа с классами
- •Глава 16.Программы из нескольких файлов
- •16.1.Работа с проектами
- •16.2.Область действия имен
- •Программа 50. Глобальные и локальные имена
- •Статические имена
- •Программа 51. Сумматор чисел
- •16.3.Заголовочные файлы
- •Страж включения
- •Понятие стека
- •Программа 52. Реализация стека в виде массива
- •16.4.Пространства имен
- •Стандартные пространства имен
- •Задачи 186-189. Работа со стеком
- •Глава 17.Перегрузка операторов
- •Программа 53. Обыкновенные дроби
- •17.1.Правила перегрузки операторов
- •Программа 54. Комплексные числа
- •Задачи 190-196. Перегрузка операторов
- •Глава 18.Конструктор копирования и оператор присваивания
- •18.1.Проблемы при копировании
- •Программа 55. Вектора на плоскости
- •Задачи 197-198. Конструктор копирования
- •Глава 19.Ввод и вывод
- •19.1.Вывод
- •19.2.Ввод
- •19.3.Ввод и вывод определяемых пользователем типов
- •Программа 56. Перегрузка операторов ввода/вывода
- •19.4.Работа с файлами
- •Программа 57. Сравнение текстового и бинарного файлов
- •Задачи 199-202. Ввод и вывод
- •Глава 20.Взаимоотношения классов
- •20.1.Объекты как члены класса
- •20.2.Конструкторы встроенных типов
- •Программа 58. Личные данные
- •20.3.Наследование
- •Пример наследования
- •Программа 59. Наследование
- •Управление доступом при наследовании
- •Наследование и конструкторы
- •Программа 60. Производный класс личных данных
- •20.4. Виртуальные функции
- •Программа 61. Невиртуальные функции
- •Программа 62. Виртуальные функции
- •20.5.Абстрактные классы
- •Программа 63. Абстрактный класс фигур
- •Вызов виртуальных функций
- •20.6. Совместимость типов
- •20.7.Множественное наследование
- •Программа 64. Системы уравнений Класс алгебраических векторов Vector
- •Класс прямоугольных матриц
- •Объявление класса Matrix
- •Реализация класса Matrix
- •Класс систем линейных уравнений
- •Пример использования классов
- •Задачи 203-212. Наследование классов
- •Глава 21.Шаблоны, исключения
- •21.1.Шаблоны
- •21.2.Шаблоны функций
- •Программа 65. Объявление и определение шаблона функции
- •21.3.Классы и шаблоны
- •Программа 66. Шаблон классов векторов
- •Программа 67. Шаблон классов динамических массивов
- •21.4.Обработка исключений
- •Программа 68. Расчет нод
- •21.5.Стандартная библиотека шаблонов
- •Программа 69. Использование шаблона векторов
- •Литература
- •Предметный указатель
- •603950, Н. Новгород, пр. Гагарина, 23
- •603000, Н. Новгород, ул. Б. Покровская, 37.
14.4.Массивы структур
Структуры, как и любые другие переменные, можно объединять в массивы. Работу с массивами структур разберем на примере.
Напишем программу, которая читает входной поток и определяет число вхождений каждого ключевого слова языка Си в читаемый текст. Для хранения ключевых слов и счетчиков можно было бы создать два параллельных массива:
char *keyword[NKEYS];
int keycount[NKEYS];
Однако для более удобной работы лучше создать массив структур.
Программа 37. Подсчет ключевых слов
Для работы с ключевыми словами и их счетчиками определим следующий массив структур:
// Файл KeyWords.cpp
struct key{ // Структура key включает два поля:
char* word; // word – указатель на ключевое слово,
int count; // count - число его вхождений в текст
} keytab[] = { // keytab - массив из структур key
"auto", 0, "break", 0, // Массив структур инициализируется
"case", 0, "char", 0, // списком ключевых слов и нулями для
"const", 0, "continue",0, // чисел вхождений.
"default", 0, "do", 0, // Отметим, что ключевые слова
"double", 0, "else", 0, // упорядочены в алфавитном порядке.
"enum", 0, "extern", 0,
"float", 0, "for", 0,
"goto", 0, "if", 0,
"int", 0, "long", 0,
"register", 0, "return", 0,
"short", 0, "signed", 0,
"sizeof", 0, "static", 0,
"struct", 0, "switch", 0,
"typedef", 0, "union", 0,
"unsigned",0, "void", 0,
"volatile", 0, "while", 0
};
Объявление структуры key используется как тип элементов массива keytab. Размер массива определяется по списку инициализации, который, строго говоря, следовало бы задавать для каждой структуры из массива в виде:
{{"auto", 0}, {"break", 0},…};
но поскольку имеется правильное чередование строк и чисел, внутренние фигурные скобки не обязательны. Ключевые слова перечисляются в алфавитном порядке, чтобы создать упорядоченный массив, с которым проще работать. Важно помнить, что сами ключевые слова, заданные строковыми константами, хранятся где-то в памяти, в структурах же key хранятся только указатели на эти строки.
// Продолжение файла KeyWords.cpp
// NKEYS - количество элементов массива keytab
int NKEYS = (sizeof keytab / sizeof(key));
Оператор sizeof может выполняться на этапе компиляции. Выражение sizeof keytab равно размеру массива keytab в байтах, выражение sizeof(key) дает размер одной структуры, отношение этих выражений есть количество элементов массива.
Предусмотрим в программе функцию fgetword для чтения из файла очередного слова и функцию binsearch для поиска ключевого слова в массиве ключевых слов.
// Продолжение файла KeyWords.cpp
#include <iostream.h>
#include <fstream.h>
#include <string.h>
#include <stdlib.h>
#include <conio.h>
#include <ctype.h>
// fgetword: читает очередное слово
int fgetword(ifstream& , char*, int);
// binsearch: бинарный поиск в упорядоченном массиве
int binsearch(char*, key*, int);
Перед тем как привести текст функции main, опишем ее работу. Программа предлагает указать имя файла, из которого следует прочитать текст, открывает файл на чтение и читает содержимое файла по одному слову. Словом считается последовательность букв и цифр, начинающаяся с латинской буквы, а также любой отдельный символ. Разделителями слов считаются пробельные символы. Каждое прочитанное слово ищется в массиве keytab с помощью функции binsearch. Если слово будет найдено в массиве, то есть является ключевым, увеличивается соответствующий счетчик. Ключевые слова, найденные в тексте, печатаются вместе со значениямия счетчиков. Далее программа просит ввести имя выходного файла, который сначала открывается на чтение. Если выходной файл удается открыть на чтение, значит файл уже существует. В этом случае программа выдает запрос на подтверждение записи в существующий файл нового содержимого. Если пользователь программы дает положительный ответ, выходной файл открывается на запись, после чего в него выводятся найденные ключевые слова и их счетчики.
// Продолжение файла KeyWords.cpp
const int MAXLENWORD = 100; // Максимальная длина слова
// Подсчет ключевых слов Си
void main()
{
int n;
char word[MAXLENWORD], c;
const int LENFN = 30; // Длина имен файлов
char inpfname[LENFN], // Имя входного
outfname[LENFN]; // и выходного файла
ifstream inpf; // Входной и
ofstream outf; // выходной файловые потоки
ifstream tmpf; // Вспомогательный файловый поток
cout << "\nВведите имя входного файла\n";
cin.getline(inpfname, LENFN); // Ввод строки с именем файла
inpf.open(inpfname); // Открытие файла на чтение
if(!inpf){ // Если не удалось открыть файл
cerr << "Не могу открыть файл " << inpfname;
exit(1); // Завершение программы
}
while(fgetword(inpf, word, MAXLENWORD) != EOF) // Пока есть слова
if(isalpha(word[0])) // Если слово начинается с латинской буквы
if((n = binsearch(word, keytab, NKEYS)) >= 0) // и ключевое,
keytab[n].count++; // увеличиваем счетчик
for(n = 0; n < NKEYS; n++) // Вывод на экран ключевых слов,
if(keytab[n].count > 0) // найденных в тексте
cout << keytab[n].count << ' ' << keytab[n].word << endl;
cout << "Введите имя выходного файла\n";
cin.getline(outfname, LENFN); // Ввод имени выходного файла
tmpf.open(outfname); // Попытка открыть выходной файл на чтение
if(!tmpf == 0){ // Если удалось, то файл существующет
cout << "Файл " << outfname << " существует. Переписать? Y/N";
if((c = cin.get()) != 'Y' && c != 'y') // Если не подтверждаем,
exit(0); // завершение программы
}
tmpf.close(); // Закрываем временный файловый поток
outf.open(outfname); // Открываем файл на запись
for(n = 0; n < NKEYS; n++) // Запись в файл
if(keytab[n].count > 0)
outf << keytab[n].count << ' ' << keytab[n].word <<endl;
getch();
}
Для поиска слова в упорядоченном по возрастанию массиве ключевых слов применен метод бинарного поиска, который состоит в следующем. Искомый элемент сравнивается со срединным элементом массива. Если искомый элемент меньше срединного, дальнейший поиск производится в первой половине массива, если больше, то во второй половине массива. При совпадении поиск заканчивается и возвращается номер найденного элемента массива. После каждого шага поиска диапазон поиска сужается в два раза. Отсюда происходит название метода. Если нижняя граница поиска превысит верхнюю, поиск прекращается как неудачный и в качестве результата возвращается –1.
// Продолжение файла KeyWords.cpp
// binsearch: найти слово в tab[0]...tab[n-1]
int binsearch(char* word, key v[], int n)
{
int cond;
int low, high, mid;
low = 0; // Нижняя граница поиска
high = n - 1; // Верхняя граница поиска
while(low <= high){
mid = (low + high) / 2; // Номер срединного элемента массива
// strcmp: стандартная функция сравнения строк
if((cond = strcmp(word, v[mid].word)) < 0)
high = mid - 1;
else if(cond > 0)
low = mid + 1;
else
return mid;
}
return -1;
}
/* fgetword: принимает следующее слово или символ из файла.
Возвращает первый символ слова. Слово – последовательность
символов, начинающаяся с буквы или одиночный символ,
не являющийся буквой */
int fgetword(ifstream& f, char* word, int lim)
{
int c;
char* w = word;
while(isspace(c = f.get())) // Пропуск пробельных
; // символов в начале слова
if(c != EOF)
*w++ = c;
if(! isalpha(c)){ // Если первый символ не буква,
* w = '\0'; // считаем ее отдельным словом
return c;
}
for( ; --lim > 0; w++) // Цикл по слову
if(!isalnum(*w = f.get())){ // Если поступила не буква и не цифра,
f.putback(*w); // возвращаем символ обратно во ввод
break; // и выходим из цикла
}
*w = '\0'; // Признак конца строки
return word[0]; // Возвращаем первый символ
}
Далее приведены диалоги с программой для двух запусков. В качестве входного файла в обоих случаях был указан файл с исходным текстом программы 34 Star.cpp. При первом запуске в качестве имени выходного файла было указано имя существующего файла. Программа это обнаружила и задала соответствующий вопрос.
Введите имя входного файла
Star.cpp
3 const
2 double
2 for
1 if
10 int
1 return
Введите имя выходного файла
Star.cpp
Файл Star.cpp существует. Переписать? Y/NN
Введите имя входного файла
Star.cpp
3 const
2 double
2 for
1 if
10 int
1 return
Введите имя выходного файла
Result36.txt
