Типы данных, определяемые пользователем. Структуры и объединения 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Типы данных, определяемые пользователем. Структуры и объединения



Краткая теория

Определение типов (typedef)

Удобно задавать используемым типам новые мнемонические имена, отражающие их суть в разрабатываемой программе.

Директива typedef позволяет задать синоним для встроенного или пользовательского типа данных. Имена, определенные с помощью директивы typedef, можно использовать точно так же, как обычные спецификаторы типов.

Синтаксис директивы typedef имеет два варианта:

 

typedef тип новое_имя;

typedef тип новое_имя [ размерность ];

 

Второй вариант используется при определении нового имени типа для массива, а квадратные скобки являются элементом синтаксиса.

Например:

 

typedef unsigned int UINT; //UINT - беззнаковое целое

typedef char msg[100]; //msg - массив из ста символов типа char

 

Объявленные таким образом имена типов используются так же, как и имена стандартных типов:

 

UINT i, j; //две переменных типа unsigned int

UINT А[10]; //массив переменных типа unsigned int

msg m; //массив (строка) из ста символов типа char

msg strs[10]; //массив из 10 строк по сто символов каждая

Перечисления (enum)

При написании программ часто возникает потребность определить несколько именованных констант, для которых требуется, чтобы все они имели различные значения (при этом конкретные значения могут быть не важны). Для этого удобно воспользоваться перечисляемым типом данных, все возможные значения которого задаются списком целочисленных констант.

Формат объявления перечисляемого типа данных:

 

enum [ имя типа ] { список_констант };

 

Здесь квадратные скобки указывают на необязательность использования.

 

Имя типа задается в том случае, если в программе требуется определять переменные этого типа. Компилятор обеспечивает, чтобы эти переменные принимали значения только из списка констант. Константы должны быть целочисленными и могут инициализироваться обычным образом. При отсутствии инициализатора первая константа будет рана нулю, а каждой следующей присваивается на единицу большее значение, чем предыдущей.

Например:

enum Err {ERR_READ, ERR_WRITE, ERR_CONVERT};

Err error;

switch (error)

{

case ERR_READ: /* операторы */ break;

case ERR_WRITE: /* операторы */ break;

case ERR_CONVERT: /* операторы */ break;

}

enum {two = 2, three, four, ten = 10, eleven, fifty = ten + 40};

 

Константам ERR_READ, ERR_WRITE, ERR_CONVERT присваивается значения 0, 1 и 2 соответственно.

Константам three и four присваиваются значения 3 и 4, константе eleven – 11. Имена перечисляемых констант должны быть уникальными, а значения могут совпадать. Преимущество применения перечисления перед описанием именованных констант и директивой typedef состоит в том, что связанные константы нагляднее; кроме того, компилятор при инициализации констант может выполнять проверку типов.

Пример программы изменения цвета текста и фона

#include <stdio.h>

#include <Windows.h>// Обязательное подключение файла

 

enum ConsoleColor {

Black = 0,

Blue = 1,

Green = 2,

Cyan = 3,

Red = 4,

Magenta = 5,

Brown = 6,

LightGray = 7,

DarkGray = 8,

LightBlue = 9,

LightGreen = 10,

LightCyan = 11,

LightRed = 12,

LightMagenta = 13,

Yellow = 14,

White = 15

};

 

int main() {

 

/*Получение дескриптора*/

HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);

 

/*Цвет всего фона - белый. Цвет всего текста - черный*/

system("color F0");

puts("Hello World!");

 

/*Цвет символов - желтый. Цвет фона - темно-серый*/

SetConsoleTextAttribute(hConsole, (WORD)((DarkGray << 4) | Yellow));

printf("Hello");

 

/*Цвет символов - светло-зеленый. Цвет фона - желтый*/

SetConsoleTextAttribute(hConsole, (WORD)((Yellow << 4) | LightGreen));

puts("World!");

 

return 0;

}

Результат работы:

 

Структуры (struct)

Структура – это объединенное в единое целое множество поименованных элементов в общем случае разных типов. В отличие от массива, все элементы которого однотипны, структура может содержать элементы разных типов.

Каждая структура включает в себя один или несколько объектов (переменных, массивов, указателей, структур и т. д.), называемых элементами структуры (компонентами).

Элементы структуры также называются полями структуры и могут иметь любой тип, кроме типа этой же структуры, но могут быть указателями на него.

Структуры, так же, как и массивы относятся к структурированным типам данных. Они отличаются от массивов тем, что, во-первых, к элементам структуры необходимо обращаться по имени, во-вторых, все поля структуры необязательно должны принадлежать одному типу.

 

struct [ имя_типа ]

{

тип_1 элемент_1;

тип_2 элемент_2;

...

тип_n злемент_n;

} [ список_описателей ];

 

Такое определение вводит новый производный тип, который называется структурным типом.

Если список описателей отсутствует, описание структуры определяет новый тип, имя которого можно использовать в дальнейшем наряду со стандартными типами

Например:

struct Worker{ // описание нового типа Worker

char fio[30];

int age, code;

double salary;

}; // описание заканчивается точкой с запятой

// определение переменной, массива типа Worker и указателя на тип Worker

Worker y, staff[100], *ps;

Если отсутствует имя типа, должен быть указан список описателей переменных, указателей или массивов. В этом случае описание структуры служит определением элементов этого списка.

 

// Определение переменной, массива структур и указателя на структуру

struct {

char fio[30];

int age, code;

double salary;

} x, staff[100], *ps;

 

Имя структуры можно использовать сразу после его объявления (определение можно дать позднее) в тех случаях, когда компилятору не требуется знать размер структуры.

struct List; // объявление структуры List

struct Link

{

List *р; // указатель на структуру List

Link *prev, *succ; // указатели на структуру Link

}

struct List { /* определение структуры List */};

 

Это позволяет создавать связные списки структур.

Для инициализации структуры значения ее элементов перечисляют в фигурных скобках в порядке их описания.

struct Worker

{

char fio[30];

int age, code;

double salary;

};

Worker ivanov = {"Иванов И.И.", 31, 215, 5800.35};

 

При инициализации массивов структур следует заключать в фигурные скобки каждый элемент массива.

struct complex

{

float re, im;

} compl [3] = { {1.3, 5.2}, {3.0, 1.5}, {1.5, 4.1}};

 

Для переменных одного и того же структурного типа определена операция присваивания, при этом происходит поэлементное копирование. Но присваивание – это и все, что можно делать со структурами целиком. Другие операции, например сравнение на равенство или вывод, не определены. Структуру можно передавать в функцию и возвращать в качестве значения функции.

Доступ к полям структуры выполняется с помощью операций выбора. (точка) при обращении к полю через имя структуры и –> при обращении через указатель.

Ввод/вывод структур, как и массивов, выполняется поэлементно.

 

Worker worker, staff[100], *ps;

 

worker.fio = "Петров С.С.";

staff[3] = worker;

staff[8].code = 123;

ps->salary = 4350.00;

 

Переменные структурного типа можно размещать и в динамической области памяти, для этого надо описать указатель на структуру и выделить под нее место

Worker *ps = new Worker; //создает переменную структурного типа

Worker *pms = new Worker[5]; //создает массив структурного типа

 

//обращение через операцию косвенного доступа

ps->age = 55;

//обращение через разыменовывание указателя

(*ps).code = 253;

 

//обращение к 0 элементу созданного массива через индекс

pms[0].salary = 5800;

 

//обращение к 1 элементу созданного массива через указатель

(*(pms + 1)).salary = 4800;

 

//очистка занимаемой памяти

delete ps;

delete []pms;

 

Если элементом структуры является другая структура, то доступ к ее элементам выполняется через две операции выбора.

struct А

{

int а;

double х;

};

 

struct В

{

А а;

double х;

};

 

B x[2];

х[0].а.а = 1;

х[0].а.x = 35.15;

х[1].х = 0.1;

Как видно из примера, поля разных структур могут иметь одинаковые имена, поскольку у них разная область видимости.

Объединения (union)

Объединение (union) представляет собой частный случай структуры, все поля которой располагаются по одному и тому же адресу. Формат описания такой же, как у структуры, только вместо ключевого слова struct используется слово union.

union [ имя_типа ]

{

тип_1 элемент_1;

тип_2 элемент_2;

...

тип_n злемент_n;

} [ список_описателей ];

 

Длина объединения равна наибольшей из длин его полей. Когда используется элемент меньшей длины, то переменная типа объединения может содержать неиспользуемую память. Все элементы объединения хранятся в одной и той же области памяти, начиная с одного адреса.

В каждый момент времени в переменной типа объединение хранится только одно значение, и ответственность за его правильное использование лежит на программисте.

Объединение применяется для следующих целей:

- экономия памяти в тех случаях, когда известно, что больше одного поля одновременно не требуется;

- интерпретация одного и того же содержимого области памяти объединения с точки зрения различных типов данных.

 

Доступ к элементам объединения осуществляется тем же способом, что и к структурам.

Заносить значения в участок памяти, выделенный для объединения, можно с помощью любого из его элементов. То же самое справедливо и относительно доступа к содержимому участка памяти, выделенного для объединения.

При определении конкретных объединений разрешена их инициализация, причем инициализируется только первый элемент объединения.

Например, пусть в магазине имеется возможность использования различных способов оплаты (кредитная карта, чек, наличные). Тогда в программе учета одновременно нам необходимо будет хранить только одно из значений, тогда как остальные нас не интересуют.

#include <iostream>

using namespace std;

int main()

{

enum paytype {СНЕСК, CARD, CASH};

paytype ptype;

union payment{

long check;

char card[25];

float sum;

}

//инициализация возможна только через первый элемент объединения

payment info = 24557695;

/* присваивание значений info и ptype */

ptype = CASH;

cin >> info.summ;

switch (ptype)

{

case CHECK: cout << "Оплата чеком: " << info.check; break;

case CARD: cout << "Оплата по карте: " << info.card; break;

case CASH: cout << "Оплата наличными: " << info.sum; break;

};

return 0;

}

 

При определении объединений без явного указания имени объединяющего типа разрешено не вводить даже имени объединения. В этом случае создается анонимное или безымянное объединение.

Объединение часто используют в качестве поля структуры, при этом в структуру удобно включить дополнительное поле, определяющее, какой именно элемент объединения используется в каждый момент. Имя объединения можно не указывать, что позволяет обращаться к его полям непосредственно.

#include <iostream>

using namespace std;

int main()

{

enum paytype {CARD, СНЕСК, CASH};

struct payment

{

paytype ptype;

union{

char card[25];

long check;

float sum;

};

};

payment info;

/* присваивание значений info и ptype */

ptype = CASH;

cin >> info.summ;

switch (info.ptype)

{

case CARD: cout << "Оплата по карте: " << info.card; break;

case CHECK: cout << "Оплата чеком: " << info.check; break;

case CASH: cout << "Оплата наличными: " << info.sum; break;

};

return 0;

}

Битовые поля

Битовые поля – это особый вид полей структуры. Они используются для плотной упаковки данных, например, флажков типа «да/нет». Минимальная адресуемая ячейка памяти – 1 байт, а для хранения флажка достаточно одного бита. При описании битового поля после имени через двоеточие указывается длина поля в битах (целая положительная константа).

struct Options

{

bool centerX:1;

bool centerY:1;

unsigned int border_type:2;

unsigned int color_index:4;

}

Битовые поля могут быть любого целого типа. Имя поля может отсутствовать, такие поля служат для выравнивания на аппаратную границу. Доступ к полю осуществляется обычным способом – по имени. Адрес поля получить нельзя, однако в остальном битовые поля можно использовать точно так же, как обычные поля структуры. Следует учитывать, что операции с отдельными битами реализуются гораздо менее эффективно, чем с байтами и словами, так как компилятор должен генерировать специальные коды, и экономия памяти под переменные оборачивается увеличением объема кода программы. Размещение битовых полей в памяти зависит от компилятора и аппаратуры.

Пример

Приведем вариант программной реализации одной из задач:

/*

1. Описать структуру с именем Man (человек), содержащую следующие поля:

• фамилия и инициалы;

• возраст;

• доход (в руб.)

2. Написать программу, выполняющую следующие действия:

• ввод с клавиатуры данных в массив, состоящий из десяти структур типа Man; записи должны быть упорядочены по возрастанию возраста;

• вывод на дисплей фамилий и доходов каждого человека;

*/

#include <stdio.h>

#include <conio.h>

#include <iostream>

using namespace std;

#define SIZE 10 // размерность строки

struct Man{

char name[SIZE]; // фамилие и инициалы

int vozrast;

float doxod;

};

//-------------------------------------

Man Init_st(int i)//вводится элементы структурa

{

Man x;

cout<<i<<"-ый человек "<<endl;

cout<<"ФИО: "; cin>>x.name;

cout<<"Возраст: "; cin>>x.vozrast;

cout<<"Доход: "; cin>>x.doxod;

return x;

}

//-------------------------------------

void Sort_el(int m, Man *x)//сортировка масс. подоходам

{

Man y; int k=1, i=0;

while(i<m && k==1){

k=0;

for(int j=0;j<m-1; j++){

if(x[j].doxod>x[j+1].doxod)

{

y = x[j]; x[j]=x[j+1]; x[j+1]=y;

k=1;

}

}

}

}

//------------------------------------

int Show_st(int m, Man *x){

for(int i=0;i<m;i++)

{

cout<<"------------------"<<endl;

cout<<"Фамилие возраст доход"<<endl;

printf("\n %10s %3d %7.3f ", x[i].name,x[i].vozrast,x[i].doxod);

}

return 0;

}

//---------------------------------------------

int main() {

setlocale(LC_ALL, "russian");

Man *a;// указатель исполь. для пред. массива

int n; // n размерность массива

cout<<"Введите кол-во элементов массива: "; cin>>n;

a=new Man[n]; //создание динамического массива

for(int i=0;i<n;i++) a[i]=Init_st(i);

Sort_el(n,a); // сортировка

Show_st(n,a); // вывод структуры

getch();

delete (a); return 0;

}

Результат работы программы:




Поделиться:


Последнее изменение этой страницы: 2016-12-11; просмотров: 320; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 18.117.165.66 (0.111 с.)