Int year;
char mon_name[4];
};
struct DATE * input_date(int day, int year, char *month)
{
struct DATE tmp;
tmp.day = day;
tmp.year = year;
strcpy(tmp.mon_name, month); // копіювання стрічки
return &tmp; // взяття адреси змінної
}
void print_date(struct DATE *d)
{
printf(“\nDate - %d %s %d\n”, d->day, d->mon_name, d->year);
}
int main(void) { struct DATE d; d = *(input_date(1, 2000,”січ”)); print_date(&d); return 0; }
|
// або елегантніше int main(void) { print_date(input_date(1, 2000,”січ”));
return 0; }
|
Розглянемо детальніше функцію void print_date(struct DATE * d). Як видно з оголошення функції, як формальний параметр використано вказівник на структуру. В такому випадку для звертання до полів структури використовується оператор “->”. Для наочної різниці між звертанням змінної типу DATE та вказівником на змінну типу DATE наведено таблицю 1.
Таблиця 1.
struct DATE d; |
struct DATE d,*d1; d1 = &d; |
d.date = 1; d.year = 2000; strcpy(d.mon_name, “січ”); |
d1->date = 1; d1->year = 2000; strcpy(d1->mon_name, “січ”); |
Структури можна об'єднувати в масив.
Тоді запис struct DATE d[5]; відображає масив з п’яти елементів типу DATE. Доступ до полів структури відбувається наступним чином:
d[0].year;
d[0].date;
Розмір структури можна взнати використавши стандартну операцію. Справа в тому що в мові "C" передбачена унарна операція sizeof, яка виконується під час компіляції, дозволяючи обчислити розмір будь-якого об’єкта. Вираз
sizeof (object)
видає ціле число, що дорівнює розміру вказаного об’єкта. (Розмір визначається в неспецифіцикованних одиницях "байти", які мають той же розмір, що і змінні типу char). Об’єкт може бути фактичною змінною, масивом і структурою, або іменем основного типу, як int або double, або іменем похідного типу, як структура. В нашому випадку
int size;
struct DATE d;
size = sizeof(d);
Структури широко використовуються при побудові різноманітних дерев та списків.
Доступ до компонентів структури
Доступ до полів структури здійснюється за допомогою оператора "." при безпосередній роботі зі структурою або "->" - при використанні вказівників на структуру. Ці оператори (. і ->) називаються селекторами членів класу. Загальний синтаксис для доступу до компонентів структури наступний:
ім'я_змінної_структури . член_даних ;
ім'я_вказівника -> ім'я_поля;
(*ім'я_вказівника) . ім'я_поля;
Наприклад:
1. Прямий доступ до елемента (оператор " . "):
datel[5].day=10;
datel[5].year=1983;
strcpy (bguіr[10].fam, "Ільків");
strcpy (bguіr[10].іm, "Сергій");
bguir[10].weіght=70.0;
bguіrtl] .heіght=180;
bguіr[і].bіrthday.day=15;
bguіr[10].bіrthday.month=l;
bguіr[10].bіrthday.year=1980;
/* Використовуючи пряме звертання до елемента, присвоюємо значення вибраній змінній. Текст поміщається в змінну, використовуючи функцію копіювання - strcpy(); */
2. Доступ по вказівнику (оператор "->"). Попередні оператори можна реалізувати в такий спосіб:
strcpy((per_ptr+10)->fam, "Ільків");
strcpy((per_ptr+l0)->іm,"Сергій");
(per_ptr+10)->weіght=70.0;
(per_ptr+10)->heіght=180;
(per_ptr+10)->bіrthday.day=15;
(per_ptr+10)->bіrthday.month=l;
(per_ptr+10)->bіrthday.year=1980;
/* Використовуючи доступ по вказівнику на структуру, присвоюємо значення відповідній змінній. Вказівник можна використовувати й так:
strcpy(*(per_ptr+10)).fam,"Ільків");
strcpy((*(per_ptr+10)).іm,"Сергій");
(*(per_ptr+10>).weіght=70.0;
(*(per_ptr+10)).heіght=180;
(*(per_ptr+10)).bіrthday.day=15;
(*(per_ptr+10)).bіrthday.month=l;
(*(per_ptr+10)).bіrthday.year=1980; */
Слід зазначити, що якщо змінна i задає номер елемента в масиві структур, то наступні оператори рівноцінні:
bguіr[і].weіght=70;
(bguіr+і)->weіght=70;
(*(bguіr+і)).weіght=70;
(per_ptr+і)->weіght=70;
(*(per_ptr+і)).weіght=70;
per_ptr[і].weіght=70;
тому що було виконане присвоювання per_ptr=bguіr; // per_ptr=&bguіr[0];
Вказівник на елемент структури має всі властивості звичайної змінної. Наприклад, якщо елемент структури є масивом символів, то per_ptr->fam - вказівником- константою на перший байт цього масиву, а per_ptr->fam[0]=’Я' запише в нього букву "Я". Сам же вказівник per_ptr визначає адресу першого байта структурної змінної й одночасно є адресою першого елемента, що входить у структуру. У нашому випадку - адресою fam[0]. Можна визначити адресу будь-якого елемента, що міститься в структурній змінній.
Наприклад:
struct person P1, P2, *р_Р1, *р_Р2;
р_Р1=&Р1; р_Р2=&Р2; // Установили вказівники на змінні
іnt *pі; // Оголошення
float *pf; // вказівників
char *pc; // на відповідний тип
//Їхня ініціалізація
pі=&p_Pl->heіght;
pf=&p_Pl->weіght;
pc=&p_P2->fam[0]; // або pc=p_P2->fam;
Можна визначити адресу змінної-структури, що є елементом іншої структури:
struct date *p_d=&p_P2->bіrthday;
p_d->day=15;
p_d->month=l ;
p_d->year=1980;
Ці оператори рівносильні наступним:
Р2.bіrthday.day=15;
Р2.bіrthday.month=l;
P2.bіrthday.year=1980;
Інший приклад оголошення шаблонів і присвоювання значень елементам змінних типу структура:
struct Poіnt /* Оголошуємо шаблони структур */
{ double х, y;
};
struct Rect
{ struct Poіnt Up_corn;
struct Poіnt Down_corn;
double length;:
double wіdth;
};
voіd maіn()
{ /* Оголошуємо змінні типу структура */
struct Poіnt p1, p2, p_arrl5];
struct Rect r1, r2;
struct Poіnt *p_ptr; // Оголошуємо вказівники
struct Rect *r_ptr; //на тип структури
// Виконання операцій над компонентами структури
pl.x=20;
p_arr[5].x=pl.x-10;
rl.Up_corn.x=p_arr[5].x;
rl.Down_corn.x-30;
rl.Up_corn.y=pl.x;
p_ptr=&pl;
p_ptr->y=35; // Використання вказівника або (*p_ptr).y=35;
p_ptr=p_arr;
(p_ptr+5)-> y-40; // (*( p_ptr+5M .y-40;
r_ ptr=&rl;
r_ptr->Down_corn.y=60; // (*(r_ptr)).Down_corn.y=60;
Структура не може містити в собі змінні свого типу, тобто наступне оголошення шаблона буде неправильним:
struct man { char *fam;
char *name;
struct man any; };
Однак структура може включати елементи, що є вказівниками на оголошений тип цієї ж структури:
struct man { char *fam;
char *name;
struct man *p_man; };
Можна визначити вказівник на оголошений тип структури й проініціалізувати його. Наприклад:
struct man group[20], studl, *pl, *p2;
pl=&studl;
p2=group; // або p2=Sgroup [0];
Установимо вказівник p_man структури group[0] на studl;
group[0].p_man " PІ; // або p2->p_man=Pl; або p2->p_man=&studl;
Нехай є визначення:
char famі[] = "Давидiв", namel[]="Андрій";
Тоді реалізація операторів:
p2->p_man->fam=faml;
p2->p_man->name=namel;
запише в структурну змінну studl у змінні fam і name відповідно адреси розміщення в пам'яті текстів "Давидiв" і "Андрій". Просування вказівника операцією ++ або -- відповідно збільшує або зменшує значення вказівника на розмір шаблона, тобто встановлює вказівник на початок іншого елемента масиву - наступного або попереднього.