Программа 39. Анализ успеваемости
В данном примере речь идет об анализе успеваемости некоторой студенческой группы в одну из экзаменационных сессий. Программа создает файл, содержащий фамилии студентов и их оценки за 4 экзамена. Пусть экзаменационная оценка может иметь 4 значения: неуд, уд, хор и отл, в этом случае для ее кодирования достаточно двух бит, так как с помощью двух бит можно создать 4 комбинации. В программе объявлена структура marks с четырьмя полями шириной по 2 бита, которые могут содержать значения оценок. Таким образом, все 4 оценки студента можно разместить в одном байте.
Для хранения как фамилии студента, так и его оценок используется структура student.
Предусмотрены два режима работы программы. Если первую строку программы записать в виде
# define EXIST_FILE 0 // Нет файла с результатами сессии
то программа попросит ввести имя создаваемого файла, в который будет записывать вводимые данные. Если первая строка имеет вид
# define EXIST_FILE 1 // Имеется файл с результатами сессии
программа работает в предположении, что файл с информацией уже существует. Программу нужно, естественно, перекомпилировать, если изменен вариант ее работы. Эти две возможности реализуются средствами препроцессора и демонстрируют условную компиляцию, когда создаются разные программы в зависимости от значения некоторого макроса. Проверка значения макроса осуществляется директивой препроцессора #if.
Для обоих вариантов работы программы выводится содержимое файла, содержащего результаты сессии, который считается бинарным.
// Файл Progress.cpp
# define EXIST_FILE 0 // Нет файла с результатами сессии
/* Макрос EXIST_FILE устанавливается в нуль,
если создается новый файл, и в единицу, если файл существует */
struct marks {
unsigned ex1: 2; // Целое значение после
unsigned ex2: 2; // двоеточия – это ширина поля в битах
unsigned ex3: 2;
unsigned ex4: 2;
};
struct student{
char fam[20]; // fam - стpока для фамилии
marks rez; // rez - поле с оценками
};
enum numbers{neud = 0, ud = 1, hor = 2, otl = 3};
/* Пеpечисление numbers вводит имена для заданных
целых значений */
#include <iostream.h>
// prn_mrk: печать оценки в словесной форме
void prn_mrk(int mrk)
{
mrk == neud ? cout << "неуд " : mrk == ud ? cout << "уд " :
mrk == hor ? cout << "хор " : cout << "отл ";
}
#include <stdlib.h>
#include <fstream.h>
#include <conio.h>
void main()
{
student st;
int m1, m2, m3, m4, i;
char filename [20]; // Массив для имени файла
fstream f; // Файловый поток
cout << "\n Программа анализа результатов сессии \n";
cout << "Введите имя файла \n";
cin.getline(filename, 20);
#if EXIST_FILE // Если файл существует
f.open(filename, ios::in|ios::binary); // Файл открывается на чтение
// как бинарный
if(!f){ // Если файл открыть не удалось
cerr << " Файл не найден \n";
exit(1); // завершение программы
}
#endif
#if !EXIST_FILE // Если файла пока нет
f.open(filename, ios::in|ios::out|ios::binary); // Файл открывается на
// чтение и запись как бинарный
if(!f){ // Если файл открыть не удалось
cerr << " Ошибка открытия файла \n";
exit(1); // завершение программы
}
cout << "Вводите фамилии студентов и их оценки "
"в виде чисел (2, 3, 4, 5). \n"
"Разделитель - пробел, конец ввода Ctrl+Z.\n";
while(cin >> st.fam >> m1 >>m2 >>m3 >> m4){ // Пока не достигнут
// конец входного потока
st.rez.ex1 = m1 - 2; // Оценки хранятся в виде,
st.rez.ex2 = m2 - 2; // уменьшенном на две единицы,
st.rez.ex3 = m3 - 2; // так как отведенные для них поля
st.rez.ex4 = m4 - 2; // могут хранить значения только от 0 до 3
// Запись информации о студенте в файл
f.write((char*)(&st), sizeof(student));
}
#endif
f.seekg(0, ios::beg); // Переход к началу файла
cout << "\n РЕЗУЛЬТАТЫ СЕССИИ \n";
// Чтение и печать содержимого файла
while(f.read((char*)&st, sizeof(student)) != NULL){
cout << st.fam << ": " << st.rez.ex1 + 2 << ", " << st.rez.ex2 + 2
<< ", "<< st.rez.ex3 + 2 << ", " << st.rez.ex4 + 2;
cout << "(";
prn_mrk(st.rez.ex1); // Печать оценок
prn_mrk(st.rez.ex2); // в словесной форме
prn_mrk(st.rez.ex3);
prn_mrk(st.rez.ex4);
cout << ")\n";
}
f.close();
getch();
}
Далее приведены результаты двух запусков программы. Первый запуск был сделан в предположении, что файл данных не существовал
(# define EXIST_FILE 0):
Пpогpамма анализа результатов сессии
Введите имя файла
rezstud.cpp
Вводите фамилии студентов и их оценки в виде чисел (2, 3, 4, 5).
Разделитель - пробел, конец ввода Ctrl+Z.
Иванов 3 4 5 3
Петров 4 4 3 5
Сидоров 4 4 5 4
^Z
РЕЗУЛЬТАТЫ СЕССИИ
Иванов: 3, 4, 5, 3( уд хор отл уд )
Петров: 4, 4, 3, 5( хор хор уд отл )
Сидоров: 4, 4, 5, 4( хор хор отл хор )
Второй запуск был сделан в предположении, что файл данных уже создан (# define EXIST_FILE 1):
Пpогpамма анализа результатов сессии
Введите имя файла
rezstud.cpp
РЕЗУЛЬТАТЫ СЕССИИ
Иванов: 3, 4, 5, 3( уд хор отл уд )
Петров: 4, 4, 3, 5( хор хор уд отл )
Сидоров: 4, 4, 5, 4( хор хор отл хор )
Задачи 167-174. Структуры
167. Дополните программу 36 выводом статистики, то есть общего количества прочитанных слов, числа различных ключевых слов, встреченных в тексте и количества ключевых слов, не вошедших в текст.
168. Измените программу 36 так, чтобы ключевые слова печатались в порядке убывания чисел их вхождений в читаемый текст.
169. Измените программу 36 так, чтобы ключевые слова печатались в порядке возрастания их чисел вхождений в читаемый текст.
170. Объединение из программы 38 позволяет получать различные значения числа с плавающей точкой путем изменения отведенных под него байтов. Напишите программу, реализующую такой способ задания чисел с плавающей точкой и установите внутреннее представление и значение наибольшего и наименьшего положительного числа типа float.
171. Напишите программу для установления внутреннего представления и значения наименьшего числа типа float и наименьшего по модулю отрицательного числа того же типа.
172. Напишите программу для анализа внутреннего представления величин типа double. Предусмотрите возможность задания различных значений переменной типа double путем записи в отведенные под нее байты некоторых значений. Исследуйте, как выглядит внутреннее представление наибольшего и наименьшего положительного значения типа double.
173. Напишите программу для установления внутреннего представления и значения наименьшего отрицательного числа типа double и наименьшего по модулю отрицательного числа этого типа.
174. Разработайте структуру с битовыми полями для хранения времени, то есть часов, минут и секунд, такую, чтобы для ее хранения отводилось как можно меньше памяти. Напишите программу, включающую функцию для печати времени в формате чч:мм:сс, где чч, мм, сс соответственно значение часов, минут и секунд, а также функцию, вычисляющую длину промежутка между двумя моментами времени.
Глава 15. Классы
До сих пор главными инструментами при решении задач у нас были функции. Программирование с использованием функций называется процедурным. В процедурном программировании основное внимание уделяется способам обработки данных, а сами данные находятся немного в стороне.
Классы являются инструментом объектно-ориентированного программирования, в котором во главе угла стоят данные.
Класс – это определяемый пользователем тип. Тип является конкретным представлением некоторой концепции. Например, встроенный тип float вместе с операциями +, -, *, / представляет конкретное воплощение математической концепции вещественного числа. Новые типы создаются для определения концепции, не выражаемой непосредственно встроенными типами.
15.1. Структуры в C++. Инкапсуляция
В языке C++ в состав структур могут входить не только данные, как это имеет место в языке C, но и функции. Объединение в структуре и данных и функций для их обработки называется инкапсуляцией. Достоинством инкапсуляции является полное описание модели в одном месте, что упрощает работу с моделью. Функции, входящие в структуру, имеют непосредственный свободный доступ к данным, хранящимся в структуре.
Например, для работы со временем суток можно использовать структуру, описанную в следующей программе.