Студопедия

КАТЕГОРИИ:


Архитектура-(3434)Астрономия-(809)Биология-(7483)Биотехнологии-(1457)Военное дело-(14632)Высокие технологии-(1363)География-(913)Геология-(1438)Государство-(451)Демография-(1065)Дом-(47672)Журналистика и СМИ-(912)Изобретательство-(14524)Иностранные языки-(4268)Информатика-(17799)Искусство-(1338)История-(13644)Компьютеры-(11121)Косметика-(55)Кулинария-(373)Культура-(8427)Лингвистика-(374)Литература-(1642)Маркетинг-(23702)Математика-(16968)Машиностроение-(1700)Медицина-(12668)Менеджмент-(24684)Механика-(15423)Науковедение-(506)Образование-(11852)Охрана труда-(3308)Педагогика-(5571)Полиграфия-(1312)Политика-(7869)Право-(5454)Приборостроение-(1369)Программирование-(2801)Производство-(97182)Промышленность-(8706)Психология-(18388)Религия-(3217)Связь-(10668)Сельское хозяйство-(299)Социология-(6455)Спорт-(42831)Строительство-(4793)Торговля-(5050)Транспорт-(2929)Туризм-(1568)Физика-(3942)Философия-(17015)Финансы-(26596)Химия-(22929)Экология-(12095)Экономика-(9961)Электроника-(8441)Электротехника-(4623)Энергетика-(12629)Юриспруденция-(1492)Ядерная техника-(1748)

Sizeof value 2 страница




У мові програмування C++ структури та об'єднання мають як об'єктно-орієнтовані, так і не об'єктно-орієнтовані атрибути. У цьому розділі детально проаналізуємо тільки останні. Об'єкт­но-орієнтовані їх властивості будемо розглядати в наступному розділі після введення таких понять як класи і об'єкти.

10.1. Робота зі структурами

10.1.1. Основні положення

У мові програмування C++ структура представляє колекцію змінних, об'єднаних загальним іменем, яка забезпечує зручний засіб зберігання споріднених даних в одному місці. Структура – це сукупність різних типів даних, оскільки вони складаються з декількох різних, але логічно взаємопов'язаних між собою змінних. З цих самих причин структури іноді називають складеними або конгломератними типами даних.

Структура – це група взаємопов'язаних між собою змінних.

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

Член структури – це змінна, яка є частиною структури.

У загальному випадку всі члени структури мають бути логічно пов'язані одна з одною! Наприклад, структури зазвичай використовують для зберігання такої інформації, як поштові адреси, банківські реквізити, елементи книжкової бібліографії і т.ін. Безумовно, відносини між членами структури абсолютно суб'єктивні і визначаються програмістом. Компілятор "нічого про них не знає" (або "не хоче знати").

Ключове слово struct означає початок оголошення структури.

Загальний формат оголошення структури має такий вигляд:

struct ім'я_типу_структури {

тип ім'я_члена_1;

тип ім'я_члена_2;

тип ім'я_члена_3;

...........

тип ім'я_члена_n;

} структурна_змінна_1, структурна_змінна_2,..., структурна_змінна_m;

Розглянемо деякі приклади оголошення структур. Визначимо структуру, яка може містити інформацію про товари, що зберігаються на складі приватної фірми. Один запис інвентарної відомості зазвичай складається з декількох даних, наприклад: назви товару, вартості та наявної кількості. Тому для керування такою інформацією зручно використовувати саме таку структуру. У наведеному нижче коді програми оголошується структура, яка визначає такі елементи: назву товару, її вартість, роздрібну ціну, наявну кількість, кількість днів до поновлення запасів. Цих даних часто цілком достатньо для керування складським господарством. Про початок оголошення структури компіляторові повідомляє ключове слово struct:

struct invStruct { // Оголошення типу структури

char nazv_tov[40]; // Назва товару

double vart_tov; // Вартість товару

double rozdr_cina; // Роздрібна ціна

int nayavna_kilk; // Наявна кількість

int kilk_dniv; // Кількість днів до поновлення запасів

};

Ім'я типу структури – це її специфікатор типу даних.

Звернемо Вашу увагу на те, що оголошення структури завершується крапкою з комою, тобто вона може бути настановою. Ім'ям типу структури тут є invStruct. Іншими словами, ім'я invStruct ідентифікує конкретну структуру даних і є її специфікатором типу.

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

invStruct inv_vidom;

Ось тепер визначається структурна змінна типу invStruct з іменем inv_vidom.

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

Під час визначення структурної змінної компілятор мови програмування C++ автоматично виділить об'єм пам'яті, достатній для зберігання всіх членів структури. На рис. 10.1 показано, як змінну inv_vidom буде розміщено в пам'яті комп'ютера (у припущенні, що double -значення займає 8 байтів, а int -значення – 4).

Рис. 10.1. Розміщення структурної змінної inv_vidom у пам'яті комп'ютера

Одночасно з оголошенням імені типу структури можна визначити одну або декілька структурних змінних:

struct invStruct { // Оголошення типу структури

char nazv_tov[40]; // Назва товару

double vart_tov; // Вартість товару

double rozdr_cina; // Роздрібна ціна

int nayavna_kilk; // Наявна кількість

int kilk_dniv; // Кількість днів до поновлення запасів

} inv_vidomA, inv_vidomB, inv_vidomC; // Визначення структурної змінної

Цей код програми оголошує структурний тип invStruct і визначає структурні змінні inv_vidomA, inv_vidomB і inv_vidomC цього типу. Важливо розуміти, що кожна структурна змінна містить власні копії членів структури. Наприклад, поле vart_tov структури inv_vidomA ізольовано від поля vart_tov структури inv_vidomB. Отже, зміни, що вносяться в певне поле однієї структурної змінної, ніяк не впливають на вміст такого самого поля іншої структурної змінної.

Якщо для коду програми достатньо тільки однієї структурної змінної, то в оголошенні структури необов'язково міститиме ім'я структурного типу. Для розуміння сказаного розглянемо такий приклад:

struct { // Оголошення типу структури

char nazv_tov[40]; // Назва товару

double vart_tov; // Вартість товару

double rozdr_cina; // Роздрібна ціна

int nayavna_kilk; // Наявна кількість

int kilk_dniv; // Кількість днів до поновлення запасів

} vidom; // Визначення структурної змінної

Цей код програми визначає одну структурну змінну vidom відповідно до оголошення структури, яка їй передує.

10.1.2. Доступ до членів структури

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

inv_vidom.vart_tov = 10.39;

Щоб звернутися до члена структури, потрібно перед його іменем поставити ім'я структурної змінної та оператор "крапка". Так здійснюється доступ до всіх членів структури. Загальний формат доступу до члена структури записується так:

ім'я_структурної_змінної.ім'я_члена_структури

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

Щоб вивести значення поля vart_tov структурної змінної inv_vidom на екран, необхідно записати таку настанову:

cout <<inv_vidom.vart_tov;

Аналогічним способом можна використовувати символьний масив inv_vidom.nazv_tov у виклику функції gets ():

gets (inv_vidom.nazv_tov);

У цьому записі функції gets () буде передано символьний покажчик на початок області пам'яті, відведеної члену nazv_tov структури inv_vidom.

Якщо виникає потреба отримати доступ до окремих елементів масиву структур під назвою, наприклад, inv_vidom.nazv_tov, необхідно використати індексацію масиву. Наприклад, за допомогою цього коду програми можна посимвольно вивести на екран вміст поля масиву структур inv_vidom.nazv_tov:

int t;

for (t=0; inv_vidom.nazv_tov[t]; t++) cout <<inv_vidom.nazv_tov[t];

cout << "\n";

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

Структури можуть бути елементами масивів, тобто, масиви структур використовуються достатньо часто. Щоб визначити масив структур, необхідно спочатку оголосити структуру, а потім визначити масив елементів цього структурного типу. Наприклад, щоб визначити 100-елементний масив структур типу invStruct (який було оголошено вище), достатньо записати таку настанову:

invStruct tovMas[100];

Щоб отримати доступ до конкретної структури в масиві структур, необхідно індексувати ім'я структури. Наприклад, щоб відобразити на екрані вміст члена nayavna_kilk третьої структури, достатньо використати таку настанову:

cout <<tovMas[2].nayavna_kilk;

Необхідно пам'ятати! Подібно до всіх елементів масиву, у масиві елементів структур їх індексування починається з нуля.

10.1.4. Приклад застосування структури

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

Запис інвентарної відомості можна зберігати в структурі типу invStruct, організовані у масиві під назвою tovMas:

const int rozmir = 100;

struct invStruct { // Оголошення типу структури

char nazv_tov[40]; // Назва товару

double vart_tov; // Вартість товару

double rozdr_cina; // Роздрібна ціна

int nayavna_kilk; // Наявна кількість

int kilk_dniv; // Кількість днів до поновлення запасів

} tovMas[rozmir]; // Визначення масиву структур

Розмір масиву вибрано довільно. При бажанні його можна легко змінити. Звернемо Вашу увагу на те, що розмірність масиву задано з використанням const -змінної. А оскільки розмір масиву в усій програмі використовується декілька разів, то застосування const -змінної для цього є виправданим. Щоб змінити розмір масиву, достатньо змінити значення константної змінної rozmir, а потім перекомпілювати програму. Використання const -змінної для визначення "магічного числа", яке часто уживається у програмі, – звичайна практика в професійному С++-коді програми.

Розроблена програма повинна забезпечити виконання таких дій:

● введення інформації про товари, що зберігатимуться на складі;

● відображення інвентарної відомості;

● модифікування полів заданого запису.

Передусім напишемо функцію main (), яка повинна мати приблизно такий вигляд:

int main ()

{

char vybir;

init_list(); // Ініціалізація масиву структур.

 

for (;;) {

// Отримання команди меню, вибраної користувачем.

vybir = menu_select();

switch (vybir) {

// Введення запису в інвентарну відомість.

case 'e': enter();

break;

// Відображення на екрані записів інвентарної відомості.

case 'd': display();

break;

// Модифікування полів наявного запису відомості.

case 'u': update();

break;

case 'q': return 0;

}

}

}

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

void init_list() // Ініціалізація масиву структур.

{

int t;

// Ім'я нульової довжини означає порожній запис.

for (t=0; t<rozmir; t++) *tovMas[t].nazv_tov = '\0';

}

Функція init_list() готує масив структур для подальшого використання, поміщаючи в перший байт поля nazv_tov нульовий символ. Передбачається, якщо поле nazv_tov порожнє, то на даний момент структура, у якій воно міститься, просто не використовується.

Функція menu_select() відображає команди меню і приймає варіант, вибраний користувачем:

int menu_select() // Отримання команди меню, вибраної користувачем.

{

char ch;

cout <<"\n";

do {

cout <<"(E)nter\n"; // Ввести новий запис.

cout <<"(D)isplay\n"; // Відобразити всю відомість.

cout <<"(U)pdate\n"; // Змінити поля запису.

cout <<"(Q)uit\n\n"; // Вийти з програми.

cout <<"Виберіть команду: ";

cin >>ch;

} while (! strchr ("eduq", tolower (ch)));

 

return tolower (ch);

}

Користувач вибирає із запропонованого меню команду, вводячи потрібну букву. Наприклад, щоб відобразити всю інвентарну відомість, потрібно натиснути букву "D".

Функція menu_select() викликає бібліотечну функцію мови C++ strchr (), яка має такий прототип:

char * strchr(const char * str, int ch);

Ця функція проглядає рядок, який адресується покажчиком str, на предмет входження в неї символу, який зберігається в молодшому байті змінної ch. Якщо такий символ виявиться, то функція поверне покажчик на нього. І у цьому випадку значення, що повертається функцією, за визначенням буде ІСТИННИМ. Однак, якщо такого збігу символів не відбудеться, то функція поверне нульовий покажчик, який за визначенням є значення ФАЛЬШ. Так перевірка тут організована для того, щоб виявити, чи є значення, що вводяться користувачем, допустимими командами меню.

Функції enter() передує виклик функції input(), яка "підказує" користувачу порядок|лад| введення даних і приймає їх. Розглянемо програмні коди обох функцій:

void enter() // Введення запису в інвентарну відомість.

{

int i;

 

// Знаходимо першу вільну структуру.

for (i=0; i<rozmir; i++)

if (!*tovMas[i].nazv_tov) break;

 

// Якщо масив повний, то значення "i" буде дорівнювати rozmir.

if (i==rozmir) {

cout <<"Перелік повний.\n";

return;

}

 

input(i); // Введення інформації.

}

void input(int i) // Введення інформації.

{

cout <<"Назва товару: "; cin >>tovMas[i].nazv_tov;

cout <<"Вартість товару: "; cin >>tovMas[i].vart_tov;

cout <<"Роздрібна ціна: "; cin >>tovMas[i].rozdr_cina;

cout <<"Наявна кількість: "; cin >>tovMas[i].nayavna_kilk;

cout <<"Кількість днів до поновлення запасів: ";

cin >>tovMas[i].kilk_dniv;

}

Функція enter() спочатку знаходить порожню структуру. Для цього перевіряється поле nazv_tov кожного (по черзі) елемента масиву tovMas, починаючи з першого. Якщо поле nazv_tov виявляється порожнім, то передбачається, що структура, до якої воно належить, ще нічим не зайнята. Якщо ж не знайдено жодної вільної структури при перевірці всього масиву структур, то значення параметра циклу i, що керує ним, дорівнюватиме його розміру. Це свідчить про те, що масив повний, і в нього вже не можна нічого додати. Якщо ж у масиві знайдеться вільний елемент, то буде викликано функцію input() для отримання інформації про товар, що вводиться користувачем. Якщо Вас цікавить, чому код введення даних про новий товар не є частиною функції enter(), то відповідь є такою: функція input() використовується також і функцією update(), про яку мова ще попереду.

Оскільки інформація про товари на складі може змінюватися, програма ведення інвентарної відомості повинна давати змогу вносити зміни в її окремі записи. Це реалізується шляхом виклику функції update():

void update() // Модифікування полів наявного запису відомості.

{

int i;

char nazva[80];

cout <<"Введіть назву товару: "; cin >>nazva;

for (i=0; i<rozmir; i++)

if (! strcmp (nazva, tovMas[i].nazv_tov)) break;

if (i==rozmir) {

cout <<"Товар не знайдено.\n";

return 0;

}

cout <<"Введіть нову назву товару.\n";

input(i); // Введення інформації.

}

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

Нам залишилося розглянути функцію display(). Вона виводить на екран інвентарну відомість в повному обсязі. Код функції display() має такий вигляд:

void display() // Відображення на екрані записів інвентарної відомості.

{

int t;

for (t=0; t<rozmir; t++) {

if (*tovMas[t].nazv_tov) {

cout <<"Назва товару:" << tovMas[t].nazv_tov << "\n";

cout << "Варт. товару:" << tovMas[t].vart_tov << " грн.\n";

cout <<"У роздріб:" <<tovMas[t].rozdr_cina << " грн.\n";

cout <<"У наявності:" <<tovMas[t].nayavna_kilk << " шт.\n";

cout <<"Залишилося:" <<tovMas[t].kilk_dniv << " днів.\n";

}

}

}

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

Код програми 10.1. Демонстрація програми ведення інвентарної відомості,
у якій використовується масив структур

#include <vcl>

#include <iostream> // Для потокового введення-виведення

#include <conio> // Для консольного режиму роботи

using namespace std; // Використання стандартного простору імен

 

const int rozmir = 100;

 

struct invStruct { // Оголошення типу структури

char nazv_tov[40]; // Назва товару

double vart_tov; // Вартість товару

double rozdr_cina; // Роздрібна ціна

int nayavna_kilk; // Наявна кількість

int kilk_dniv; // Кількість днів до поновлення запасів

} tovMas[rozmir]; // Визначення масиву структур

 

// Оголошення процедур і функцій

void enter(), init_list(), display();

void update(), input(int i);

int menu_select();

 

int main () // Початок основної програми

{

char vybir;

init_list(); // Ініціалізація масиву структур.

 

for (;;) {

// Отримання команди меню, вибраної користувачем.

vybir = menu_select();

switch (vybir) {

// Введення запису в інвентарну відомість.

case 'e': enter();

break;

// Відображення на екрані записів інвентарної відомості.

case 'd': display();

break;

// Модифікування полів наявного запису відомості.

case 'u': update();

break;

case 'q': return 0;

}

}

} // Кінець основної програми

 

// Визначення процедур і функцій

void init_list() // Ініціалізація масиву структур.

{

int t;

 

// Ім'я нульової довжини означає порожній запис.

for (t=0; t<rozmir; t++) *tovMas[t].nazv_tov = '\0';

}

 

int menu_select() // Отримання команди меню, вибраної користувачем.

{

char ch;

cout << "\n";

do {

cout << "(E)nter\n"; // Ввести новий запис.

cout << "(D)isplay\n"; // Відобразити всю відомість.

cout << "(U)pdate\n"; // Змінити поля запису.

cout << "(Q)uit\n\n"; // Вийти з програми.

cout << "Виберіть команду: ";

cin >> ch;

} while (! strchr ("eduq", tolower (ch)));

 

return tolower (ch);

}

 

void enter() // Введення запису в інвентарну відомість.

{

int i;

 

// Знаходимо першу вільну структуру.

for (i=0; i<rozmir; i++)

if (!*tovMas[i].nazv_tov) break;

 

// Якщо масив повний, то значення "i" буде дорівнювати rozmir.

if (i==rozmir) {

cout << "Перелік повний.\n";

return;

}

input(i); // Введення інформації.

}

 

void input(int i) // Введення інформації.

{

cout << "Назва товару: "; cin >> tovMas[i].nazv_tov;

cout << "Вартість товару: "; cin >> tovMas[i].vart_tov;

cout << "Роздрібна ціна: "; cin >> tovMas[i].rozdr_cina;

cout << "Наявна кількість: "; cin >> tovMas[i].nayavna_kilk;

cout << "Кількість днів до поновлення запасів: ";

cin >> tovMas[i].kilk_dniv;

}

 

void update() // Модифікування полів наявного запису відомості.

{

int i;

char nazva[80];

 

cout << "Введіть назву товару: "; cin >> nazva;

 

for (i=0; i<rozmir; i++)

if (! strcmp (nazva, tovMas[i].nazv_tov)) break;

 

if (i==rozmir) {

cout << "Товар не знайдено.\n";

return;

}

cout << "Введіть нову назву товару.\n";

input(i); // Введення інформації.

}

 

void display() // Відображення на екрані записів інвентарної відомості.

{

int t;

for (t=0; t<rozmir; t++) {

if (*tovMas[t].nazv_tov) {

cout <<"Назва товару:" << tovMas[t].nazv_tov << "\n";

cout <<"Варт. товару:" << tovMas[t].vart_tov << " грн.\n";

cout <<"У роздріб:" <<tovMas[t].rozdr_cina << " грн.\n";

cout <<"У наявності:" <<tovMas[t].nayavna_kilk << " шт.\n";

cout <<"Залишилося:" <<tovMas[t].kilk_dniv << " днів.\n";

}

}

}

10.1.5. Присвоєння структур

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

Код програми 10.2. Демонстрація можливості присвоєння значень структурним змінним

#include <vcl>

#include <iostream> // Для потокового введення-виведення

#include <conio> // Для консольного режиму роботи

using namespace std; // Використання стандартного простору імен

struct demoStruct { // Оголошення типу структури

int a, b;

};

 

int main ()

{

demoStruct strVar1, strVar2;

strVar1.a = strVar1.b = 10;

strVar2.a = strVar2.b = 20;

cout <<"Структури до присвоєння.\n";

cout <<"strVar1: " << strVar1.a << " " << strVar1.b<<"\n";

cout <<"strVar2: " << strVar2.a << " " << strVar2.b<<"\n\n";

 

strVar2 = strVar1; // Присвоєння структур

cout <<"Структури після присвоєння.\n";

cout <<"strVar1: " << strVar1.a << " " << strVar1.b<<"\n";

cout <<"strVar2: " << strVar2.a << " " << strVar2.b <<"\n";

 

getch (); return 0;

}

Внаслідок виконання цієї програми на моніторі буде відображено такі результати:

Структури до присвоєння.

strVar1: 10 10

strVar2: 20 20

 

Структури після присвоєння.

strVar1: 10 10

strVar2: 10 10

У мові програмування C++ кожне нове оголошення структури визначає новий тип. Отже, навіть якщо дві структури фізично однакові, але мають різні імена типів, компілятор вважатиме їх різними і не дасть змоги присвоїти значення однієї з них інший. Розглянемо такий фрагмент коду програми. Він некоректний і тому не скомпілюється:

struct demoStructA {

int a, b;

};

struct demoStructB {

int a, b;

};

 

int main()

{

demoStructA strVar1;

demoStructB strVar2;

 

strVar2 = strVar1; // Помилка через невідповідності типів.

.....

}

Незважаючи на те, що структури demoStructA і demoStructB фізично однакові, з погляду компілятора вони є окремими типами.

Необхідно пам'ятати! Одну структуру змінну можна присвоїти іншій тільки у тому випадку, якщо обидві вони мають однаковий тип.

10.1.6. Передача структури функції як аргументу

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

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

Код програми 10.3. Демонстрація механізму передачі структури функції як аргументу




Поделиться с друзьями:


Дата добавления: 2014-11-29; Просмотров: 496; Нарушение авторских прав?; Мы поможем в написании вашей работы!


Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет



studopedia.su - Студопедия (2013 - 2024) год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! Последнее добавление




Генерация страницы за: 0.237 сек.