Типы данных пользователя.ppt
- Количество слайдов: 71
Типы данных, определяемые пользователем
Язык С++ позволяет программисту определять свои типы данных и правила работы с ними (типы данных, определяемые пользователем). К ним относятся: • переименования типов (typedef), • структуры (struct), • перечисления (enum), • объединения (union).
Переименование типов (typedef) Для того чтобы сделать программу более ясной, можно задать типу новое имя с помощью ключевого слова typedef: typedef тип новое_имя[размерность]; Например : typedef unsigned int typedef char Msg[100]; UINT;
Введенное таким образом имя можно использовать таким же образом, как и имена стандартных типов: UINT i, j; //две переменных типа unsigned int Msg str[10]; // массив из 10 строк по 100 символов
Перечисления (enum) При необходимости определить несколько именованных констант, имеющих различные значения, используют перечисления. Формат: enum [имя_типа] {список_констант}; Константы должны быть целочисленными и могут инициализироваться. При отсутствии инициализатора первая константа обнуляется, следующая – на единицу больше и т. д.
enum Err {ER_READ, ER_WRITE, ER_CONVERT}; Err error; . . . switch (error) { case ER_READ: . . break; case ER_WRITE: . . . break; case ER_CONVERT: . . break; } Константам ER_READ, ER_WRITE, ER_CONVERT присваиваются значения 0, 1 и 2 соответственно.
Структуры В отличии от массива структура может содержать элементы разных типов (поля структуры). Определение структуры состоит из двух шагов: 1. объявление шаблона структуры; 2. определение переменных типа объявленного шаблона.
Описание шаблона структуры: struct [имя типа] { тип 1 элемент1; Тип 2 элемент2; . . Тип. N элемент. N; } [список_описателей]; Если отсутствует имя типа, то должен быть список описателей – список переменных, указателей или массивов.
Например, объявление шаблона: struct sotr { char fam[15]; char dolg[20]; int oklad; };
Новый тип sotr можно использовать в дальнейшем, например: sotr odin; // переменная odin типа sotr msotr[10]; // массив msotr из 10 сотрудников
Доступ к полям структуры выполняется с помощью оператора выбора: 1. . (точка) при обращении через имя структуры : odin. oklad msotr[6]. fam 2. -> при обращении через указатель : student->rating sphere->radius
Пример1 Список 5 -и сотрудников кафедры содержит фамилии, должности и оклады. Вывести на экран фамилии сотрудников, имеющих максимальный оклад и его размер. #include
// Инициализация массива структур sotr msotr[n]= { "Петров", "Зав. кафедрой", 40000, "Иванов", "Профессор", 40000, "Шубина", "Преподаватель", 10000, "Семенов", "Лаборант", 5000, "Ильина", "Ассистент", 6000 }; void main() { long int max; int i;
max=0; for(i=0; i
Пример 2 // Объявляем новый тип данных TStudent struct TStudent { char FIO[56]; // ФИО char Group[10]; //название группы int Year; // курс float Rating; // рейтинг }; //Объявляем указ-ль на структ. данных struct TStudent *Student;
// Создаём студента struct TStudent Zuev = {“Зуев А. А. ”, “И-12 -10”, 1, 20. 6}; Student = &Zuev; Student->Rating = 25. 1; // или (*Student). Rating= 25. 1;
Битовые поля Это особый вид полей структуры, используемых для плотной упаковки данных. После имени поля через двоеточие указывается длина поля в битах. Битовые поля могут быть любого целого типа.
Например: struct Options { bool center: 1; unsigned int shadow: 2; unsigned int palette: 4; }
Объединение (union) - частный случай структуры, все поля которой располагаются по одному адресу. В каждый момент времени в переменной типа объединение хранится только одно значение. Объединения применяют для экономии памяти.
#include
switch (pt) { case CARD: printf(“Оплата по карте %s”, info. card); break; case CHECK: printf(“Оплата чеком %ld”, info. check); break; } }
Директивы препроцессора
Препроцессор – первая фаза компилятора. Инструкции препроцессора называются директивами. Директивы начинаются с символа #.
Директива #include <файл> Вставляет содержимое указанного файла в ту точку исходного файла, где она записана. < > - поиск ведётся в стандартном каталоге включаемых файлов; “ “ - поиск ведётся в каталоге с исходным файлом, а затем в стандартном каталоге.
Заголовочные файлы обычно имеют расширение. h и могут содержать: • Определения типов, констант, шаблонов, перечислений; • Объявления функций, данных, шаблонов; • Пространства имён; • Директивы препроцессора; • Комментарии.
В заголовочном файле не должно быть определений функций и данных.
Директива #define Определяет подстановку в тексте программы. Она используется для определения: • Символических констант: #define имя текст_подстановки • Макросов (выглядят как функции, но реализуются подстановкой их текста в текст программы): #define имя(параметры)текст_подст.
• Символов, управляющих условной компиляцией (используется вместе с #ifdef и #ifndef): #define имя Примеры: #define Version 1 #define Vasya “Василий Иванович” #define Мах(x, y) ((x)>(y))? (x): (y) #define MUX Имена рекомендуется записывать прописными буквами.
В С++ вместо символических констант предпочтительнее использовать const и enum , вместо макросов – функции или шаблоны.
Директивы условной компиляции #if, #ifdef, #ifndef применяются, чтобы исключить компиляцию отдельных частей программы. Это полезно при отладке или при поддержки нескольких версий программы для различных платформ.
#if константное_выражение. . . [ #elif константное_выражение. . . ] [ #else. . . ] #endif
#if VERSION == 1 #define INCFILE “vers 1. h” #elif VERSION == 2 #define INCFILE “vers 2. h” #else #define INCFILE “vers 3. h” #endif #include INCFILE
Директивы #ifdef и #ifndef позволяют управлять компиляцией в зависимости от того, определён ли с помощью #define указанный в них символ или нет. #ifdef символ // код компилируется, если символ определён #ifndef символ // код компил-ся, если символ не определён
Действие этих директив распростаняется до первого #elif, #else или #endif. Пример: #ifndef FILE_INCLUDED #define FILE_INCLUDED “myheader. h” #endif. . . #include FILE_INCLUDED
Ввод и вывод. Работа с файлами
Имеется 2 основных типа функций вводавывода: • Потоковые – данные при вводе/выводе рассматриваются как поток байтов. Обеспечивается буферизованный (форматированный или неформатированный) ввод/вывод. • Низкоуровневые – непосредственно обращаются к средствам ввода-вывода операционной системы. Не выполняют буферизации и форматирования (open, close, read, write).
Поток - последовательность байтов (символов), не зависящая от устройства ввода/вывода (файл, принтер, клавиатура, дисплей и т. д. ). Буфер потока – вспомогательный участок основной памяти, куда помещаются данные перед их выводом на устройство вывода или перед их передачей в основную память при вводе.
Особенность потоковой обработки данных : элементы данных можно посылать или считывать из потока только последовательно. Рассматриваются только однонаправленные потоки (данные передаются в одном направлении). Из программы данные можно отправить (записать) в поток вывода, а получить (прочитать) их из потока ввода.
Использование буфера повышает скорость передачи данных, так как пересылки осуществляются только тогда, когда буфер уже заполнен (при выводе) или пуст (при вводе). В зависимости от устройства ввода/вывода потоки делятся на: • Стандартные (клавиатура и дисплей), • Строковые (символы потока образуют строку в основной памяти), • Файловые.
Потоковый ввод/вывод в С++ реализуется либо с помощью функций, унаследованных от С (
Потоковый в/в в С Заголовочный файл -
Операции в/в начинаются с текущей позиции потока, определяемой положением указателя потока. Основные функции в/в потока: • Чтение и запись потока байтов fread, fwrite; • Чтение символа из потока getc, fgetc, из стандартного потока stdin-getchar; • Запись символа в поток putc, fputc, в стандартный поток stdout- putchar; • Чтение строки из потока fgets, из стандартного потока stdin - gets;
• Запись строки в поток fputs, в стандартный поток stdout- puts; • Форматированный ввод из потока – fscanf, из стандартного потока stdinscanf, из строки - sscanf; • Форматированный вывод в поток – fprintf, в стандартный поток stdoutprintf, в строку - sprintf;
Работа с потоком на примере работы с файлом: 1) Открытие потока. Поток можно открыть для чтения и записи в двоичном или текстовом режиме. Формат: FILE* fopen(const char* filename, const char* mode); первый параметр – имя файла, второй – режим открытия файла:
“r” – для чтения, “w” – пустой файл для записи (существующий файл стирается), “a”- для добавления информации в конец файла, “r+” – существующий файл для чтения и записи, “w+” – пустой файл для чтения и записи (существующий файл стирается), “a+” – для чтения и добавления информации в конец.
В режиме открытия могут быть символы t (текстовый режим) и b (двоичный режим) - по умолчанию текстовый режим. При успешном открытии функция возвращает указатель на структуру типа FILE (указатель на файл), в противном случае – NULL. Пример: FILE* f=fopen(“d: \cpp\data”, ”rb”);
2) Ввод/вывод в поток – в виде последовательности байтов, в виде символов и строк или с использованием форматирования (см. список потоковых функций)
3) Закрытие потока Поток закрывается при завершении программы либо с помощью функции fclose: int fclose(FILE*);
#include
Для перемещения по файлу можно использовать функции: 1. int fseek(FILE *f, long bt, int where); Установка указателя на заданную позицию: Bt – на сколько байтов сместить, Where =0 – смещать от начала файла, =1 – от текущей позиции указателя, =2 – от конца файла
2. long ftell(FILE *f); Возвращает значение указателя на текущую позицию файла (в байтах от начала файла). В случае ошибки возвращает -1. 3. void rewind(FILE *f); Возвращает указатель на начало файла.
Потоковый ввод/вывод в стиле С++ Потоки cin, cout, cerr (
Список функций для работы с файловыми потоками хранится в заголовочном файле fstream. h ( #include
1. Создание потоков ifstream in_stream; /*создаётся файловый поток ввода с именем in_stream (in_stream-объект класса ifstream)*/ ofstream out_stream; //создаётся файловый поток вывода с именем out_stream 2. Подключение и отключение потоков После создания потока его можно подключить к файлу с помощью метода open.
in_stream. open("Lecture_4. txt"); /* подключили поток “in_stream” к началу файла Lecture_4. txt */
out_stream. open("Lecture_4. txt"); /* подключили поток "out_stream" к файлу "Lecture_4. txt", прежнее содержимое файла будет удалено */
Для отключения потока "in_stream" от файла (для закрытия файла) вызывают метод close(): in_stream. close();
Аналогично для потока вывода: out_stream. close(); - добавляет в конец файла служебный символ EOF (end-of-file). Если данные не записывались, то создаётся пустой файл:
3. Проверка ошибок файловых операций Простейший способ проверки - вызов метода fail(): in_stream. fail(); - возвращает True, если последняя операция привела к ошибке (например, была попытка открытия несуществующего файла). После ошибки поток может быть поврежден, поэтому лучше не продолжать работу с ним.
#include
4. Символьный ввод/вывод 4. 1. Функция ввода get (чтение символа из файла) in_stream. get(ch);
4. 2. Функция вывода put (запись символа в файл): out_stream. put('Л');
5. Проверка конца файла (функция eof()) В класс "поток ввода" встроен флаг EOF (конец файла) и метод eof() для чтения этого флага. Ниже приведена программа для копирования текстового файла "Lecture_4. txt" одновременно и на экран, и в другой файл "Copy_of_4. txt".
#include
while ( !in_stream. eof() ) { cout << character; out_stream. put(character); in_stream. get(character); } out_stream. close(); in_stream. close(); return 0; }
>" и "<<" Объекты классов ofstream and ifstream всегда работают с" src="https://present5.com/presentation/3/134168901_132542173.pdf-img/134168901_132542173.pdf-66.jpg" alt="7. Операторы ввода/вывода ">>" и "<<" Объекты классов ofstream and ifstream всегда работают с" />
7. Операторы ввода/вывода ">>" и "<<" Объекты классов ofstream and ifstream всегда работают с файлами как с последовательностями символов. Данные других типов ("int", "double" и др. ) для записи в файл должны быть преобразованы в последовательность символов. При чтении из файла эти последовательности должны быть преобразованы обратно.
>" и "<<". out_stream << 437 <<" src="https://present5.com/presentation/3/134168901_132542173.pdf-img/134168901_132542173.pdf-67.jpg" alt="Некоторые преобразования типов данных автоматически выполняются операторами ">>" и "<<". out_stream << 437 <<" />
Некоторые преобразования типов данных автоматически выполняются операторами ">>" и "<<". out_stream << 437 << ' '; in_stream >> n; При использовании операторов ">>" и "<<" надо после каждого записанного значения записывать еще как минимум один пробел или 'n' (маркер конца строки). Тогда данные будут отделены в файле друг от друга, и их можно будет извлекать оттуда с помощью оператора ">>".
Пример Сначала программа создает файл "Integers. txt", записывает в него целые числа 51, 52, 53, 54 и 55, а затем считывает эти числа из файла. #include
// Создание файла out_stream. open("Integers. txt"); for(count=1; count<=5; count++ ) out_stream << number++ << ' '; out_stream. close(); // Подсчет количества целых чисел в файле in_stream 1. open("Integers. txt"); count=0; in_stream 1 >> number; while ( !in_stream 1. eof()) { count++; in_stream 1 >> number; }
in_stream 1. close(); cout<<"В файле "<
В отличие от функции get(), оператор >> игнорирует в файле разделители (пробелы).


