Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
knrc (1).pdf
Скачиваний:
12
Добавлен:
12.02.2016
Размер:
925.69 Кб
Скачать

Роздiл 6

Структури

Структура — це набiр з однiєї або бiльше змiнних, можливо рiзних типiв, зiбраних разом пiд одним iм’ям для зручного манiпулювання ними. (Структури також називають записами в iнших мовах, а саме Pascal.) Структури допомагають органiзувати складнi данi, особливо у великих програмах, оскiльки вони дозволяють розглянути групу спорiднених змiнних як єднiсть, а не розрiзненi одиницi.

Однiєю з типових структур є список зарплатнi: опис працiвника складається з набору ознак, таких як iм’я, адреса, номер соцiального забезпечення, оклад тощо. Деякi з цих ознак, в свою чергу, теж могли би бути структурами: iм’я має декiлька складових, те саме стосується адреси або навiть окладу. Iнший, типовiший для C, приклад пов’язаний з графiкою: пункт складається з пари координат, прямокутник — з пари пунктiв i так далi.

Основною змiною, привнесеною стандартом ANSI, є опис присвоєння структурам — структури можна копiювати та надавати їм нових значень, їх може бути передано функцiям i повернуто функцiями. Цi риси пiдтримувались бiльшiстю компiляторiв впродовж багатьох рокiв, але стандарт сформулював їх точнiше. Автоматичнi структури та масиви тепер також пiдтримуються.

6.1Основнi поняття про структури

Створiмо тепер декiлька структур, придатних для графiки. Основним об’єктом є пункт, який має координати x i y, обидвi цiлi числа.

Цi двi складовi можна помiстити в структуру, оголошену як:

struct point { int x; int y;

};

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

145

146

РОЗДIЛ 6. СТРУКТУРИ

яку називають етикеткою структури (як point у цьому прикладi). Етикетка присвоює назву структурi, i може використовуватись пiзнiше як скорочення для частин, оголошених у фiгурних дужках.

Змiннi, вказанi всерединi, називаються елементами структури. Елемент структури, етикетка та звичайна, не включена в структуру, змiнна можуть мати ту саму назву, не створюючи конфлiкту, оскiльки вони завжди роздiленi контекстом. Бiльше того, тi самi назви елементiв можуть повторюватись у рiзних структурах, хоча, з мiркувань стилю, таке використання назв можна застосувати хiба що для тiсно взаємопов’язаних об’єктiв.

Саме оголошення struct визначає новий тип. За правою закривною дужкою може слiдувати список змiнних, так само як i у випадку iнших основних типiв. Тобто, вираз

struct { ... } x, y, z;

синтаксично аналогiчний

int x, y, z;

у тому сенсi, що обидва вирази оголошують змiннi x, y i z як певного типу i зумовлюють вiдведення для них мiсця.

Оголошення структури, за яким не слiдує список змiнних, не зарезервує мiсця для зберiгання; воно тiльки описує зразок або форму структури. Однак, якщо оголошення включає етикетку, цю етикетку можна використати пiзнiше для означення окремих взiрцiв структури. Так, наприклад, використовуючи вищенаведене оголошення point,

struct point pt;

визначить змiнну pt, яка є структурою типу struct point. Структуру (змiнну типу struct) можна започаткувати, якщо додати до її означення список iнiцiалiзаторiв, кожен з яких — це сталий вираз для окремих елементiв структури:

struct point maxpt = { 320, 200 };

6.1. ОСНОВНI ПОНЯТТЯ ПРО СТРУКТУРИ

147

Автоматичну структуру також можна iнiцiювати через присвоєння або шляхом виклику функцiї, що повертає структуру правильного типу.

Елемент певної структури можна вказати в якомусь виразi конструкцiєю, що має форму

назва-структури.елемент

Оператор елемента структури . (крапка) зв’язує назву структури з одним з її елементiв. Щоб вивести координати пункту pt, наприклад, нам потрiбно вказати

printf("%d,%d", pt.x, pt.y);

або, щоб обчислити вiдстань вiд початку координат (0,0) до pt,

double dist, sqrt(double);

dist = sqrt((double)pt.x * pt.x + (double)pt.y * pt.y);

Структури можуть гнiздитися. Одним з представлень прямокутника може бути два пункти, що знаходяться у протилежних кутах:

struct rect {

struct point pt1; struct point pt2;

};

Структура rect включає двi структури point. Якщо ми оголосимо screen як

struct rect screen;

тодi

screen.pt1.x

посилається на координату x елемента pt1 структури screen.

148

РОЗДIЛ 6. СТРУКТУРИ

6.2Структури та функцiї

Єдиними чинними операцiями зi структурами є їхнє копiювання, або присвоєння значення їм як цiлому, здобуття їхньої адреси за допомогою &, та доступ до її членiв. Копiювання та присвоєння включають передачу аргументiв функцiям так само як повернення значень функцiями. Структури неможливо порiвняти. Структуру можна iнiцiювати списком сталих значень членiв структури; можна також започаткувати автоматичну структуру за допомогою присвоєння.

Давайте займемося дослiдженням структур шляхом написання декiлькох функцiй для роботи з пунктами прямокутника. Iснує, принаймнi, три можливих пiдходи до цiєї проблеми: передача складових окремо, передача цiлої структури, або передача покажчика на неї. Кожна з цих метод має свої переваги й недолiки.

Перша функцiя makepoint вiзьме в якостi аргументiв два цiлих, i поверне структуру point:

/* makepoint: утворює пункт зi складникiв x та y */ struct point makepoint(int x, int y)

{

struct point temp;

temp.x = x; temp.y = y; return temp;

}

Звернiть увагу, що мiж назвою аргументу й елементом структури з тим самим iм’ям конфлiкту не має; навпаки, повторне використання назви тiльки пiдкреслює взаємозалежнiсть.

makepoint тепер можна використати для динамiчної iнiцiалiзацiї структури, або подання структури як аргумент функцiї:

struct rect screen; struct point middle;

struct point makepoint(int, int);

screen.pt1 = makepoint(0,0); screen.pt2 = makepoint(XMAX, YMAX);

middle = makepoint((screen.pt1.x + screen.pt2.x)/2, (screen.pt1.y + screen.pt2.y)/2);

Наступним кроком є створення набору функцiй для арифметичних дiй з пунктами. Наприклад

6.2. СТРУКТУРИ ТА ФУНКЦIЇ

149

/* addpoints: додає два пункти */

struct addpoint(struct point p1, struct point p2)

{

p1.x += p2.x; p1.y += p2.y; return p1;

}

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

Як iнший приклад, функцiя ptinrect перевiряє, чи пункт знаходиться всерединi прямокутника, основуючись на нашiй умовi, що прямокутник включає лiву та нижню межу, а не верхню та праву:

/* ptinrect: повертає 1, якщо p всерединi r, 0 - якщо нi */ int ptinrect(struct point p, struct rect r)

{

return p.x >= r.pt1.x && p.x < r.pt2.x && p.y >= r.pt1.y && p.y < r.pt2.y;

}

Це передбачає, що прямокутник представлено в стандартнiй формi, де координати pt1 меншi за координати pt2. Наступна функцiя повертає прямокутник, гарантовано в канонiчнiй формi представлення:

#define min(a, b) ((a) < (b) ? (a) : (b)) #define max(a, b) ((a) > (b) ? (a) : (b))

/* canonrect: стандартизує координати прямокутника */ struct rect canonrect(struct rect r)

{

struct rect temp;

temp.pt1.x = min(r.pt1.x, r.pt2.x); temp.pt1.y = min(r.pt1.y, r.pt2.y); temp.pt2.x = max(r.pt1.x, r.pt2.x); temp.pt2.y = max(r.pt1.y, r.pt2.y); return temp;

}

150

РОЗДIЛ 6. СТРУКТУРИ

Якщо функцiї потрiбно передати велику структуру, то загалом ефективнiше вказати покажчик, чим копiювати цiлу структуру. Покажчики на структуру подiбнi на покажчики на звичайнi змiннi. Оголошення

struct point *pp;

вказує на те, що pp — це покажчик на структуру типу struct point. Якщо pp вказує на структуру point, то *pp — це сама структура, a (*pp).x та (*pp).y — це члени структури. Для використання pp, ми могли би написати, наприклад,

struct point origin, *pp; pp = &origin;

printf("origin is (%d,%d)\n", (*pp).x, (*pp).y);

Дужки обов’язковi у випадку (*pp).x, оскiльки прiоритет оператора елемента структури . бiльший за *. Вираз *pp.x означає *(pp.x), що неправильно тому, що x не є покажчиком.

Покажчики на структури використовуються настiльки часто, що було надано альтернативне позначення для скорочення. Якщо p — це покажчик на структуру, тодi

p->член-структури

посилається на певний елемент. Таким чином, ми могли би написати натомiсть

printf("origin is (%d,%d)\n", pp->x, pp->y);

Обидва, . та -> спрягаються злiва направо, тож якщо ми матимемо

struct rect r, *rp = &r;

то наступнi чотири вирази еквiвалентнi:

r.pt1.x rp->pt1.x (r.pt1).x (rp->pt1).x

Структурнi оператори . iз ->, разом iз () виклику функцiй i [] iндексiв знаходяться на верхiвцi iєрархiї прiоритету, тож спрягаються дуже тiсно. Отже, наприклад, якщо ми маємо оголошення

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