Типы данных, определяемые пользователем
Встроенные типы данных, а также непосредственно основанные на них массивы и указатели могут служить базой для создания новых составных (смешанных) типов данных достаточно сложной конфигурации. Язык C предоставлял пользователю (программисту) возможность создавать свои собственные типы данных: задавать перечисление с помощью ключевого слова enum, определять составной тип (структуру, битовое поле, объединение), вводить новое обозначение типа с помощью ключевого слова typedef.
Перечисленные возможности используют:
· перечисление – список именованных числовых констант целого типа (рассмотрено в разделе 10.2);
· структура – совокупность переменных, объединенных по некоторому признаку, рассматриваемая как нечто единое;
· битовые поля – разновидность структуры, предоставляющая доступ к отдельным битам;
· объединение – разновидность структуры, позволяющая одному участку памяти содержать данные различных типов;
· ключевое слово typedef, которое дает новое имя существующему типу или именует новый составной тип.
Исторически сложилось, что эти типы данных называют типами данных, определяемыми пользователем.
Язык С++ добавил к списку этих типов классы, а также наделил существовавшие составные типы (в частности, структуру) новыми свойствами. Однако для лучшего понимания сути составного типа данных целесообразно вначале рассмотреть его в трактовке языка C, упомянув о расширении его возможностей в C++ позднее.
Переопределяемые типы данных
Программист может определить свои типы данных, переименовав уже существующие. Это можно сделать с помощью ключевого слова typedef.
Формат простого переопределения типа:
typedef тип новый_тип ;
Введенное таким образом имя можно использовать так же, как и имена стандартных типов, например, оператор
typedef unsigned int UINT;
переопределяет тип unsigned int, переименовывая его в UINT. После такого объявления UINT становится синонимом типа unsigned int в программе, например,
UINT i,j;
объявляет переменные i и j только что введенного типа UINT.
Структуры
Не все совокупности данных, используемые в реальной жизни, состоят из однотипных элементов, как массивы. Пример – различные ведомости и таблицы, строки которых содержат числовые и текстовые данные. Составной тип данных, предназначенный для манипулирования подобными данными, называется структурой. Структура языка С аналогична "записи" (record) языка Pascal.
Для работы со структурой необходимо описать ее состав, для чего следует определить шаблон структуры, используя, например, формат:
struct имя {
тип_1 элемент_1 ;
тип_2 элемент_2 ;
...
тип_n элемент_N ;
};
Ключевое слово struct указывает, что объявляется структура. За ним следует имя шаблона структуры, идентифицирующее описываемую структуру для того, чтобы можно было создавать переменные этого типа. Далее в фигурных скобках располагается описание элементов (полей) структуры, которые, в отличие от элементов массивов, могут быть различных типов.
Пример:
struct Worker { // описание нового типа Worker
int code;
char fio[30];
int age;
double salary;
} ; // описание заканчивается точкой с запятой
Идентификаторы в списке объявлений элементов должны быть уникальны. Однако они могут совпадать с идентификаторами элементов других структур и с идентификаторами обычных переменных.
Объявление шаблона структуры описывает определяемый пользователем тип данных, но не создает переменной этого типа. Для создания такой переменной необходимо ее объявить, например, так:
struct Worker worker; // объявление переменной worker типа Worker
В языке С при объявлении переменной структурного типа наличие ключевого слова struct являлось обязательным. В языке С++ это не так, достаточно имени шаблона структуры:
Worker worker;
В этих в объявлениях struct Worker (в C++ – Worker) играет ту же роль, что и, например, int или float в объявлениях обычных переменных. Переменная объявленного структурного типа содержит указанную в описании шаблона последовательность величин заданного типа.
При объявлении переменной структурного типа компилятор выделяет память для каждого элемента структуры. Элементы структуры размещаются в памяти последовательно в том же порядке, в котором они объявляются. Память каждому элементу выделяется на границе, соответствующей его типу. Поэтому в памяти могут появиться неиспользуемые неименованные участки между соседними элементами. Вследствие этого размер переменной структурного типа не всегда равен сумме размеров ее элементов. Для определения действительного размера структурной переменной следует использовать операцию sizeof.
Как и переменные других типов, структуры при их объявлении можно инициализировать. Для инициализации структуры значения ее элементов перечисляют в фигурных скобках в соответствующем порядке. Например:
struct {
int code;
char fio[30];
int age;
double salary;
} worker = { 3124, "Ivanoff", 31, 3400.55};
Как и для массивов, указывать пустые значения в списке нельзя, недостающие значения принимаются нулевыми, лишние вызывают соответствующее сообщение компилятора об ошибке.
Для доступа к элементам (полям) структуры используется операция . (“точка”, выбор), связывающая имя структурной переменной и имя ее элемента:
int iAge = worker.age;
worker.code = 3125;
strcpy (worker.fio, "Sidoroff");
cout << worker.salary;
Для переменных одного и того же структурного типа определена операция присваивания, при этом происходит поэлементное копирование. Так, для
Worker worker2;
worker2 = worker;
элементы worker2 получат значения соответствующих элементов worker.
Массивы структур
Как видно из шаблона структуры Worker, массивы могут быть элементами структур. В свою очередь и переменные одного и того же структурного типа могут объединяться в массивы. Пример объявления массива структур:
Worker staff [100]; // массив из 100 структур типа Worker
При инициализации массивов структур удобно заключать в фигурные скобки список значений для каждой структуры:
Worker worker[2] = { { 3124, "Ivanoff", 31, 3400.55},
{ 3125, "Petroff", 35, 3900.00} };
Можно не структурировать фигурными скобками данные для инициализации, тогда они будут присваиваться полям структур в порядке их расположения.
Пример доступа к полям массива структур:
staff[8].age = 30;
cout <<staff[5].fio;
char c = staff[7].fio[0];