русс | укр

Мови програмуванняВідео уроки php mysqlПаскальСіАсемблерJavaMatlabPhpHtmlJavaScriptCSSC#DelphiТурбо Пролог

Компьютерные сетиСистемное программное обеспечениеИнформационные технологииПрограммирование


Linux Unix Алгоритмічні мови Архітектура мікроконтролерів Введення в розробку розподілених інформаційних систем Дискретна математика Інформаційне обслуговування користувачів Інформація та моделювання в управлінні виробництвом Комп'ютерна графіка Лекції


Структури та функції


Дата додавання: 2014-11-28; переглядів: 887.


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

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

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

/* makepoint: утворює пункт зі складників x та y */

struct point makepoint(int x, int y)

{

struct point temp;

 

temp.x = x;

temp.y = y;

return temp;

}

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

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

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);

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

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

struct addpoint(struct point p1, struct point p2)

{

p1.x += p2.x;

p1.y += p2.y;

return p1;

}

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

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

/* ptinrect: повертає 1, якщо p всередині r, 0 - якщо ні */

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;

}

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

#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;

}

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

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);

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

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

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

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

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

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

struct rect r, *rp = &r;

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

r.pt1.x

rp->pt1.x

(r.pt1).x

(rp->pt1).x

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

struct {

int len;

char *str;

} *p;

то

++p->len

здійснює приріст len, а не p, оскільки неявні дужки виглядають як ++(p->len). Дужки можна використати, щоб змінити спрягання (зв'язування): (++p)->len збільшує p перед тим як дістатися до len, тоді як (p++)->len збільшує p після. (Цей останній набір дужок необов'язковий.) Подібно до цього, *p->str добуває значення, на яке вказує str; *p->str++здійснює приріст str після доступу до того, на що вона вказує (схоже до *s++); (*p->str)++збільшує те, на що вказує str; a *p++->str збільшує p після доступу до того, на що вказуєstr.


<== попередня лекція | наступна лекція ==>
Основні поняття про структури | Масиви структур


Онлайн система числення Калькулятор онлайн звичайний Науковий калькулятор онлайн