Структури. Синтаксично структури задаються так:
struct[<тег>]{<список оголошення елементів>}<описувач>
Інша форма
struct<тег><описувач>[…<описувач>]
використовується у випадку, коли тег відповідної структури вже визначений, тобто знаходиться в межах області дії. Наприклад:
struct point {int x,
int y;} A,B;
struct {int x; float y;} Z,S;
Доступ до елемента структури здійснюється у два способи. Якщо визначено екземпляр структури, то доступ здійснюється конструкцією вигляду <описувач>.<ім’я поля>. У випадку, коли оголошено покажчик на екземпляр структури, доступ здійснюється з використанням операції ->:
<покажчик>-><ім’я поля>
struct point *pa;
…
pa->x=4;
Структури можуть бути вкладеними, тобто полем структури також може бути структура:
struct line {int d;
struct point a;
struct point b;}
L1,L2;
Доступ здійснюється так:
L1.a.x=2;
L2.b.y=3;
Використовуємо стільки операцій доступу, скільки є рівнів вкладеної структури. Якщо оголосити покажчик на структуру line
struct line *pl;
то доступ здійснюється так:
(pl->a).x=4;
|
|
У мові С обмежено набір операцій зі структурами як з єдиним цілим. Допускається присвоювання структур у випадку, коли вони мають однакові поля. Структури можуть повертатися функціями, виступати їхніми аргументами. Допускається використання масивів структур:
struct point k[6];
При роботі зі структурами можна проводити спеціальний розподіл пам'яті для полів, використовуючи так звані бітові поля. Синтаксично вони задаються так:
<поле>:<константа>
Наприклад:
struct bit{
int i:1;
int p:5;
int l:3;
};
Тоді поле i займатиме 1, р – 5, l – 3 біти.
Об'єднання. Синтаксично об'єднання задаються аналогічно структурам:
union[<тег>]{<список оголошення елементів>}<описувач>
union<тег><описувач>[…<описувач>]
Наприклад:Union u_tag
{
int ival;
float fval;
char *pval;
} uval;
Об'єднання мають деякі спільні властивості зі структурами: однаковий механізм доступу до полів, можна задавати бітові поля тощо. Специфіка об'єднання полягає в тому, що всі поля мають однакову адресу в пам'яті (однаковий зсув). Присвоєння значення якомусь полю приведе до втрати інформації, що зберігалася в іншому до цього присвоєння. У різні моменти часу об’єднання може містити об'єкти різних типів і розмірів. Це і є його основним призначенням. У наведеному фрагменті програми змінна uval матиме достатній розмір, щоб зберігати найбільший із трьох типів незалежно від машини, на якій здійснюється компіляція – програма не буде залежати від характеристик апаратних засобів. Будь-яка змінна із цих трьох типів може бути присвоєна uvar і потім використана у виразах. Справа програміста – стежити за тим, який тип зберігається в об'єднанні в даний момент. Синтаксично доступ до членів об'єднання здійснюється аналогічноструктурам:Ім’яОб’єднання. Ім’яЧленачи
|
|
Якщо для відстеження типу, збереженого в даний момент в uval, використовується змінна utype, то можна написати такий фрагмент програми:
if (utype==int)
printf("%d\n", uval.ival);
else if (utype==float)
printf("%f\n", uval.fval);
else if (utype==string)
printf("%s\n", uval.pval);
Else
printf("bad type %d in utype\n", utype);
Об'єднання можуть бути полями структур, і навпаки. Для звертання до поля об'єднання в структурі використовується механізм, аналогічний механізму доступу у вкладених структурах. Наприклад, у масиві структур
struct {
char *name;
int flags;
int utype;
union {
int ival;
float fval;
char *pval;
} uval;
} symtab[nsym];
на змінну ival можна посилатися так:
symtab[i].uval.ivalа на перший символ рядка pval так:
*symtab[i].uval.pval