Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

lr08

.pdf
Скачиваний:
8
Добавлен:
19.02.2016
Размер:
889.63 Кб
Скачать

Лабораторна робота № 8

Перелічуваний тип даних, структури, об’єднання

Мета роботи

Метою даної лабораторної роботи є отримання практичних навичок роботи з типамипереліками, об'єднаннями та структурами з використанням мови С++.

Короткі теоретичні відомості до роботи

Перелічуваний тип даних

При використанні великої кількості логічно пов’язаних констант зручно користуватись типом-переліком (перелічуваним типом).

Перелік має вид

enum [Name] { item1 [=def], item2 [=def],

. . .

itemN [=def]};

де

enum — ключове слово (від enumerate — перелічувати),

Name — ім’я (тег) списку констант (необов’язкове),

item1 … itemN — перелік констант цілого типу,

[=def] — параметр ініціалізації констант (необов’язковий).

Наприклад, описати роботу світлофора можна за допомогою трьох констант, які відповідають червоному (RED), жовтому (YELLOW) або зеленому (GREEN) сигналу:

const int RED = 0; const int YELLOW = 1; const int GREEN = 2;

Використовуючи перелік, те ж саме можна зробити в один рядок:

enum COLOR {RED, YELLOW, GREEN};

Якщо при визначенні переліку значення константи не вказане, то воно автоматично задається на одиницю більшим значення попередньої константи. Перша константа має значення 0. Тому в переліку COLOR автоматично RED=0, YELLOW=1, GREEN=2.

Той же перелік можна ініціалізувати іншими значеннями:

enum COLOR {RED=13, YELLOW=1, GREEN};

При цьому константа GREEN матиме значення 2 як і раніше.

Ім’я переліку Name задається в тому випадку, якщо в програмі необхідно визначати змінні даного типу-переліку. Компілятор забезпечить, щоб змінні такого типу приймали значення зі списку констант. Наприклад, можна оголосити змінні іменованого типу-переліку COLOR:

COLOR c1 = RED, c2;

1

Приклад переліку, який об’єднує константи, але на відміну від COLOR не має власного імені:

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

У списку переліку можуть міститися елементи, які мають однакові значення, проте ідентифікатор кожної константи у списку має бути унікальним. Крім того, ідентифікатор елемента списку переліку повинен бути відмінним від ідентифікаторів елементів всіх інших списків переліків, а також взагалі від інших ідентифікаторів.

Змінні перелічуваних типів можуть використовуватись в арифметичних виразах. При виконанні арифметичних операцій значення перелічуваних типів перетворюються в цілі числа. Однак зворотне перетворення автоматично не виконується. Наступний приклад викличе помилку при компіляції (не дивлячись на те, що константа RED = 0 присутня в переліку):

enum COLOR {RED, YELLOW, GREEN};

COLOR c1 = 0; //Помилка!

Коректна ініціалізація c1 виглядає так:

COLOR c1 = (COLOR) 0; //Правильно!

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

Weekdays d1 = SA, d2 = SU, d3 = WE, d4;

 

d4

= (Weekdays) (d1

+ d2);

// Обережно з обчисленнями!

d4

= (Weekdays) (d1

- d2);

// Результат

може не потрапити

d4

=

(Weekdays)

(TH *

FR);

//

в область

визначення

d4

=

(Weekdays)

(WE /

TU);

//

перерахування

Структури

Як правило, об’єкти, які представляються в програмі, володіють рядом різноманітних властивостей і, що дуже важливо, різнотипних властивостей. Так, наприклад, об’єкт книга може бути представлена в програмі такими властивостями, як назва (тип рядок), автори (тип масив рядків), кількість сторінок (тип ціле додатне число). Для роботи з подібними об’єктами в програмі зручно об’єднати всі властивості об’єкта в єдиний набір даних. Конструкція, яка дозволяє в C++ об’єднувати різнотипні дані, і таким чином створювати програмну модель деякого об’єкта, це — структура.

Структура може бути представлена як деякий набір різнотипних і/або однотипних даних, сукупність яких розглядається як абсолютно новий тип даних користувача.

Оголошення структур

Перед будь-яким використанням структур треба оголосити структурний тип. Структура оголошується за допомогою ключового слова struct, за яким йде необов'язкове ім'я тегу для створення нового типу даних і шаблон структури у фігурних дужках. По шаблону створюватимуться змінні структурного типу. Шаблон містить оголошення полів або членів структури, які розділені крапку з комою. Оголошення поля складається з вказівки типу і імені змінної:

struct ім’я_структурного_типу { тип_поля1 ім'я.поля1; тип_поля2 ім'я.поля2;

. . .

тип_поляN ім'я.поляN;

};

2

Опис структури закінчується символом крапка з комою (;).

Наприклад, оголосимо типи даних, що моделюють об’єкти "точка на площині" та "особа":

struct Point { double х; double у;

};

struct Person { char name[20]; char surname[20]; int yearOfBirth;

};

Використання структурованих даних в тілі програми можливе у тому випадку, якщо буде оголошений який-небудь об'єкт (змінна) нового типу. Наприклад, для приведеного вище прикладу Person можна вказати:

Person aPerson, personArray[10], *personPtr;

Тут aPerson — змінна типу Person, personArray — масив з 10 елементами типу Person, personPtr — покажчик на об’єкт Person.

Змінну структури можна також оголосити, розмістивши її ім’я в кінці об’яви структури:

struct MyStruct

{

char str [50]; int a, b;

} S, *pS, arrS[12];

При оголошенні змінних структурних типів, як і інших типів, можна ініціалізувати. Для цього треба записати список ініціалізаторів через кому в фігурних дужках. Приклад оголошення і ініціалізації змінних структурного типу Point і Person, оголошених у попередньому прикладі:

Point pt = {10.5, 15.2};

Person student = {"Іван", "Проспав" 1910};

Доступ до полів структури

Для доступу до полів структури використовуються дві операції:

операція точка (.);

операція стрілка (->).

Операція точка (.) використовується для доступу до полів через ім’я змінної або посилання структурного типу.

Вякості прикладу заповнимо поля об’єкта типу Person.

//Оголошення змінної структурного типу (об’єкта)

Person worker;

//Заповнення полів об’єкта strcpy(worker.name, "Остап"); strcpy(worker.surname, "Безсонний"); worker.yearOfBirth = 1990;

cout << worker.surname << endl; //Виведення прізвища на екран. //Використана операція точка

Як видно з прикладу числовим даним виконується звичайне присвоєння, тоді як поля-рядки заповнюються за допомогою функції strcpy().

3

Операція стрілка (->) забезпечує доступ до поля структури через покажчик на об’єкт. Як згадувалось вище програміст може оголошувати змінні-покажчики на структуру. Приклад оголошення та використання покажчика на структуру Person:

//Оголошення змінної типу покажчика на структуру

Person *pWorker;

//Покажчику на структуру присвоюється адреса змінної (об’єкта) pWorker = &worker;

cout << pWorker->name << endl; //Виведення імені на екран через покажчик. //Використана операція стрілка

Масиви структур

Сам по собі один єдиний запис типу структури у більшості випадків навряд чи може викликати підвищений інтерес. Проте у разі, коли структуровані дані об'єднуються в масиви, мова може йти вже не про одиничний об'єкт, а про цілу базу даних.

Припустимо, що в програмі створюється база даних, яка містить інформацію про житлові будинки мікрорайону. Структуру, яка буде містити інформацію про житловий будинок, можна оголосити так:

struct HOUSE

 

{

 

unsigned short RegNum;

//Номер мікрорайону

char Street[51];

//Вулиця

char HouseNum[6];

//Номер дому

unsigned short MaxFloorNum;

//Кількість поверхів

unsigned short MaxFlatNum;

//Кількість квартир

bool Parking;

//Наявність стоянки

};

 

Сама база даних повинна об’єднувати інформацію про декілька будинків і може бути представлена як масив змінних структурного типу HOUSE. Оголошення масиву структур відрізняється від оголошення звичайних масивів лише тим, що в якості типу створюваного масиву вказується тип структури. Таким чином, для створення бази даних, що містить інформацію про тридцять будинків мікрорайону, можна оголосити наступний масив:

HOUSE mDistr[30];

Доступ до елементів такого масиву здійснюється звичайним способом, наприклад, по індексу (індексація ведеться, починаючи з нуля). Доступ до полів будь-якого елементуструктури масиву здійснюється також стандартно — через оператор точка (.) Наступний фрагмент коду здійснює в циклі впорядковане заповнення номерів будинків структури HOUSE, а потім виводить записані дані в стовпчик на екран:

HOUSE mDistr[30];

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

itoa(i+1, mDistr[i].HouseNum, 10); for (int i = 0; i < 30; i++)

cout << mDistr[i].HouseNum << '\n';

В даному фрагменті для виконання перетворення цілого числа в рядок символів використана функція itoa().

4

Структури як аргументи функцій

Якщо в тіло функції необхідно передати інформацію, структуровану за певним принципом, то зручно при цьому в якості параметра функції використовувати структурний тип. Для цього в прототипі функції вказується тип даних користувача, сформований при оголошенні структури. Наприклад, якщо була оголошена структура

struct ALLNUMB

{

int nVar; long lVar; short shVar;

unsigned int uiVar;

};

прототип функції буде мати вид:

void Func(ALLNUMB);

При виклику такої функції відбувається передача в тіло функції аргументу типу структури за значенням (копія аргументу). Таким чином, оригінал структурованого об'єкту модифікації не підлягає. Функція може також повертати об'єкт типу структури:

ALLNUMB Func2(ALLNUMB);

В цьому випадку модифіковані дані при виході з функції не загубляться, а будуть передані в точку виклику функції.

Розглянемо приклад передачі у функцію описаної раніше структури HOUSE для виведення на екран назви вулиці і номера будинку, що містяться в ній.

// Структурний тип як аргумент функції

#include "stdafx.h" #include <iostream>

using namespace std;

struct HOUSE

{

unsigned short RegNum; char Street[51];

char HouseNum[6];

unsigned short MaxFloorNum; unsigned short MaxFlatNum; bool Parking;

};

void OutAddress(HOUSE);

int _tmain(int argc, _TCHAR* argv[])

{

HOUSE MyHouse;

MyHouse.RegNum = 524; strcpy(MyHouse.Street, "вул. Гоголя"); strcpy(MyHouse.HouseNum, "2-a"); MyHouse.MaxFloorNum = 7; MyHouse.MaxFlatNum = 84; MyHouse.Parking = true;

OutAddress(MyHouse);

return 0;

}

5

void OutAddress(HOUSE house)

{

cout << house.Street << ", "; cout << house.HouseNum << endl;

}

вул. Гоголя, 2-a

Виклик функції OutAddress(MyHouse) передає в тіло сформовану структуру, доступ до членів якої здійснюється відповідно до описаного вище правила, через оператор 'точка' (.).

В якості аргументів в тіло функції можуть бути передані посилання і покажчики на структури даних. При цьому значно знижується час (порівняно з передачею за значенням), за який цей параметр передається у функцію, а також економиться пам'ять стеку програми.

Синтаксис прототипу функції при передачі структур за допомогою покажчиків і посилань ідентичний синтаксису передачі параметрів простих типів через покажчики і посилання:

//Прототип функції, яка приймає покажчик і посилання на цілу змінну bool Func(int* ptr, int& ref);

//Прототип функції, яка приймає покажчик і посилання на структуру типу HOUSE char Func2(HOUSE* pMh, HOUSE& rMh);

Таким чином, у функцію Func2 будуть передані не самі значення структур, а відповідні адреси, що значною мірою економить пам'ять стеку.

Функцію OutAddress(MyHouse) з попереднього прикладу можна переробити так, щоб вона приймала покажчик на структуру HOUSE. Прототип функції:

void OutAddress(HOUSE*);

Визначення функції:

void OutAddress(HOUSE* house)

{

cout << house->Street << ", "; cout << house->HouseNum << endl;

}

При виклику переробленої функції необхідно вже передавати покажчик на структуру:

OutAddress(&MyHouse);

Ще один приклад роботи зі структурами і переліками:

// Приклад використання структур та переліків

//

#include "stdafx.h" #include <iostream>

using namespace std;

int _tmain(int argc, _TCHAR* argv[])

{

enum USex { male = 0, female, unisex };

char *textSex[] = { "male", "female", "unisex" };

struct PersonInfo

{

char

name[30];

char

surname[30];

short

age;

USex

sex;

char

group[5];

};

 

6

 

PersonInfo pi[]

=

 

 

 

 

 

 

{

 

 

 

 

 

 

 

 

{ "Alex",

"Ivanoff",

21, male,

"BOOM" },

 

{ "Olga",

"Smirnov",

19, female, "BIIM" },

 

{ "Tanya",

"Petrenko",

18, female,

"BMII" },

 

{ "Serg",

"Taranko",

22,

male,

"DMBB"

},

 

{ "",

"",

 

0,

unisex, ""

}

 

};

 

 

 

 

 

 

 

 

int i, count = sizeof(pi) / sizeof(PersonInfo);

 

 

for( i = 0; i <

count; i++ )

 

 

 

 

 

{

 

 

 

 

 

 

 

 

printf( "%d

%-7s %-11s %3d %-7s %6s\n", i,

 

 

 

pi[i].name, pi[i].surname, pi[i].age,

 

 

 

textSex[pi[i].sex], pi[i].group );

 

 

}

 

 

 

 

 

 

 

 

return

0;

 

 

 

 

 

 

}

 

 

 

 

 

 

 

 

0

Alex

Ivanoff

21

male

 

BOOM

 

 

1

Olga

Smirnov

19

female

BIIM

 

 

2

Tanya

Petrenko

18

female

BMII

 

 

3

Serg

Taranko

22

male

 

DMBB

 

 

4

 

 

0

unisex

 

 

 

 

 

 

 

 

 

 

 

 

Об’єднання

У C++ є особлива конструкція, оголошення якої нагадує синтаксис оголошення структури, але яка має абсолютно інший фізичний сенс.

Об'єднання служить для розміщення в одній і тій же області пам'яті (за однією і тією ж адресою) даних різних типів. Очевидно, що в окремий момент часу в пам'яті може знаходитися тільки один з вказаних при оголошенні об'єднання типів.

Оголошення об'єднання розпочинається з ключового слова union, за яким йде ідентифікатор і блок опису елементів різного типу, наприклад:

union MyData

{

int iVar1;

unsigned long ulFreq; char Symb[10];

};

При цьому в пам'яті компілятором резервується місце для розміщення найбільшого елементу об'єднання, в даному випадку — 10 байт під символьний масив (рис. 1).

Змінні

int iVar1 unsigned long ulFreq char Symb[10]

4 байти

4 байти

10 байт

Одна область пам’яті для всіх змінних (10 байт)

Рис. 1. Змінні об’єднання використовують одну область пам’яті

Тут необхідно наголосити, що неможливо зробити так, щоб це об’єднання зберігало і ціле значення iVar1, і беззнакове ulFreq, і масив Symb[10] одночасно, оскільки вони накладаються в пам’яті одне на одне.

7

Об’єднання використовують для економії пам’яті у тих випадках, коли відомо, що більше одного поля одночасно непотрібно. Об’єднання також служать для перетворення даних одного типу в іншій. Часто об'єднання включають до складу структур.

Доступ до елементів об'єднання виконується за допомогою операції 'точка' (.).

На відміну від структур, змінна типу об'єднання може бути ініціалізована тільки значенням першого оголошеного члена (в даному випадку — цілою змінною iVar1) :

MyData myX = {25};

Розглянемо приклад використання об'єднання для збереження номеру чеку або номеру картки при оплаті. Причому одночасно може зберігатись лише номер картки або лише номер чеку.

// Приклад використання обєднань

#include "stdafx.h" #include <iostream>

using namespace std;

int _tmain(int argc, _TCHAR* argv[])

{

enum paytype {CARD, CHECK};

paytype ptype;

// Обєднання, яке дозволяє зберігати номер картки або номер чеку union payment

{

char card[26]; long check;

} info;

int nChoice;

cout << "Вкажіть спосіб оплати (0 - карта, 1 - чек): "; cin >> nChoice;

ptype = (paytype) nChoice;

switch (ptype)

{

case CARD:

cout << "Введіть номер карти: "; getchar(); cin.getline(info.card, 26);

cout << "Оплата по карті #" << info.card << endl; break;

case CHECK:

cout << "Введіть номер чеку: "; cin >> info.check;

cout << "Оплата чеком #" << info.check << endl; break;

default:

cout << "Неправильний вибір способу оплати" << endl; break;

}

return 0;

}

Вкажіть спосіб оплати (0 - карта, 1 - чек): 1

Введіть номер чеку: 23421 Оплата чеком #23421

8

В даному прикладі для коректної обробки вмісту змінної типу об’єднання payment необхідно зберігати змінну ptype, що вказує який тип даних (CARD або CHECK) зберігається в об’єднанні в даний час. Для того, щоб зібрати відомості про поточний тип даних, записаних в об’єднанні і саме об’єднання в єдиний об’єкт, об'єднання часто використовують як поле структури. При цьому в структуру зручно включити додаткове поле для визначення який саме елемент об'єднання використовується в кожен момент. Ім'я об'єднання можна не вказувати, що дозволяє звертатися до його полів безпосередньо через точку або стрілку, як до інших полів структури:

struct {

paytype ptype; union {

char card[25]; long check;

};

} info;

/*... надання значення полям info */

switch (info.ptype)

{

case CARD:

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

case CHECK:

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

}

В програмі можуть бути використані масиви об’єднань як і інших типів.

union UType { float f; int i;

};

//оголошення та ініціалізація масиву елементів типу union

UType au[6]= { 0.5, -2.2, 0.4, 5, 8, 12 };

//значення елементів масиву будуть ініційовані результатами приведеня

//до типу першого елементу з UType, тобто до типу float.

9

Порядок виконання роботи

1.Створити проект Консольної програми Win32, в якому будуть реалізовані наступні пункти роботи.

2.Створити перелічуваний тип та декілька змінних даного типу, виконати декілька довільних операцій над змінними (арифметичні операції та операції порівняння).

3.Створити структуру Student яка буде містити персональну інформацію про студента з наступними полями:

ПІБ;

рік народження;

назва групи;

номер залікової книжки;

стать (задати як перелік).

4.Оголосити масив з 5 елементів типу структури Student і ініціалізувати його. Використовуючи індексування елементів масиву, пройти всі елементи масиву і змінити значення будь-якого поля для кожного елемента-структури масиву (наприклад задати всім студентам одну групу).

5.Написати функцію, яка приймає покажчик на структуру Student, та використовуючи даний покажчик виводить інформацію про студента на екран. За допомогою цієї функції вивести вміст всіх елементів масиву студентів на екран.

6.Оголосити об’єднання MyUn, для зберігання елементів типи, яких відмічені у варіанті до роботи (табл. 1). Створити масив з 15 елементів типу MyUn. Заповнити елементи даного масиву випадковими значеннями з правилом:

елементи масиву з індексом 0, 3, 6, 9, 12 містять значення типу першого елемента об’єднання MyUn;

елементи масиву 1, 4, 7, 10, 13 містять значення типу другого елемента об’єднання

MyUn;

елементи масиву 2, 5, 8, 11, 14. містять значення типу третього елемента об’єднання

MyUn.

7.Обчислити суму елементів масиву з п.6 кожного типу окремо.

10

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]