2. Вложени структури. Рекурсивно използване на структури.
Тип на структура може да включва като полета други структури; те от своя страна също могат да притежават структурни полета и т.н.
например:
struct person
{ char name[30];
int born, died;
};
struct book
{ char name[40];
struct person author;
int year;
float price;
};
ако вложената структура е дефинирана предварително (както по-горе), тя може да се използва за дефиниране на отделни структурни променливи;
struct book b1, b2, *pb;
struct person per1, per2, *ptrper;
има възможност самата дефиниция да е вложена:
struct book
{ char name[40];
struct person
{ char name[30];
int born, died;
} author;
int year;
float price;
}
в този пример имаме вложена дефиниция, като областта на видимост на вложени я тип структура е дефиницията на включващата го структура и той не може да се използва за дефиниране на самостоятелни структурни променливи; в такъв случай става безсмислено указването на име на вложения тип структура;
достигане на полетата при вложени структури:
b1.author.name, b1.author.born – прилагане на операцията ‘.’ два пъти (тя е ляво-асоциативна);
pb = &b1;
int p;
p = pb->author.born; - комбиниране на операция ‘->’ с операция ‘.’;
реално операцията ‘->’ тук не е нужна; има случаи, когато е нужно използването на ‘->’ - когато е известен адресът, но не и името на променливата;
поле на структура може да бъде указател;
пример:
struct point
{ int k;
int *p;
int *q;
} ;
struct point var; //дефиниране на структурна променлива от тип
point;
обръщането към полетата на променливата var, които са указатели се осъществява по общоприетия начин: var.p, var.q; полетата, които са указатели могат да участват във всички допустими адресни операции; например:
*var.p – това е стойността, записана в адреса, сочен от указателя p; не поставяме скоби, защото операция ‘.’ е с по-голям приоритет;
типът на указателите, описани в тялото на структурата може да е всеки допустим тип, включително и структура; C и C++ не допускат поле от една структура да бъде структура от същия тип;
няма проблеми поле, което е указател да сочи към структура от същия тип; например:
struct linkedlist
{ int field;
struct linkedlist *next;
} ;
в такъв случай говорим за рекурсивно използване на структура; чрез него могат да се създават и обработват данни, организирани в списъци, или имащи дървовидна структура; обикновено, при тях се използва динамично заделяне на памет;
3. Функции и структури.
Указател към структура може да се предаде като параметър на функция; по този начин се осигурява достъп в тялото на функцията до полетата на структурна променлива, дефинирана извън функцията; обръщението към самите полета се осъществява с указателната операция ‘->’;
върната величина от една функция може да е указател към структура;
примерна програма:
#include
struct type
{ int a[5];
int k;
};
void main ()
{ struct type ksi = { 1, 6, 3, 7, 2, 1}, eps = { 2, 8, 9, 0, -5, 2},
*p = &ksi, *q = &eps;
struct type *maxi (struct type *, struct type *);
// функцията maxi има параметри два указателя към структурата
// type и връща указател към тази структура;
printf ( “ Стойността на k е: %d\n”, maxi(p, q)->k);
}
struct type *maxi (struct type *u, struct type *v)
{ int i, s1 = 0, s2 = 0;
for (i = 0; i < 5; i++)
{ s1 += u->a[i];
s2 += v->a[i];
}
if (s1>s2) return u;
else return v;
}
в тази реализация, ако променим формалния параметър, това ще промени и съответния фактически параметър;
изложеният начин за предаване на структури като параметри (чрез указатели) е универсален – той се поддържа в K&R C, в ANSI C и в C++;
в ANSI C и в C++ може директно да се предава структура като параметър на функция; формалният параметър се описва в заглавието като структура; обръщението към полетата на структурата в тялото се осъществява с операцията ‘.’;
в ANSI C и C++ структура може да бъде върната като резултат от изпълнението на функция; в този случай типът на връщания резултат се описва като структура;
извикването на функция с параметър структура е свързано с допълнителен разход на време и памет, защото се записва копие на цялата структура в програмния стек; при това промяната на копието не влияе на структурата, която е фактически параметър; по същата причина, когато връщаната стойност на една функция е структура се губи време и памет за записване в програмния стек на копие на тази структура;
ако масив е поле на структура, то предавайки структурата по стойност ние подаваме и масива по стойност – това е начинът за предаване на масив по стойност;
примерната програма (с предаване по стойност):
#include
struct type
{ int a[5];
int k;
};
void main ()
{ struct type ksi = { 1, 6, 3, 7, 2, 1}, eps = { 2, 8, 9, 0, -5, 2} ;
struct type maxi (struct type, struct type);
printf ( “ Стойността на k е: %d\n”, maxi(ksi, eps).k);
}
struct type maxi (struct type u, struct type v)
{ int i, s1 = 0, s2 = 0;
for (i = 0; i < 5; i++)
{ s1 += u.a[i];
s2 += v.a[i];
}
if (s1>s2) return u;
else return v;
}
в тази реализация, ако променим формалния параметър, това не засяга съответния фактически параметър;
само в C++ има още един начин за предаване на структура като параметър и връщане на структура като резултат от функция; в C++ може да се предава структура по име като параметър на функция, като формалният параметър се опише като псевдоним; обръщението към полетата на структурата в тялото на функцията се осъществява с операцията ‘.’; също така само в C++ име на структура може да бъде върнато като резултат от функция; в този случай типът на връщания резултат се описва като псевдоним;
#include
struct type
{ int a[5];
int k;
};
void main ()
{ struct type ksi = { 1, 6, 3, 7, 2, 1}, eps = { 2, 8, 9, 0, -5, 2} ;
struct type &maxi (struct type &, struct type &);
printf ( “ Стойността на k е: %d\n”, maxi(ksi, eps).k);
}
struct type &maxi (struct type &u, struct type &v)
{ int i, s1 = 0, s2 = 0;
for (i = 0; i < 5; i++)
{ s1 += u.a[i];
s2 += v.a[i];
}
if (s1>s2) return u;
else return v;
}
съпоставяне на трите подхода:
-
с указатели - поддържа се от K&R C, ANSI C, C++; предимства – оптимален по време и памет; недостатъци – работи с указатели;
-
с предаване по стойност (директно) – поддържа се от ANSI C и C++; предимства – по-естествен запис, по-просто за програмиране; недостатъци – разход на време и памет;
-
с псевдоними – поддържа се от C++; обединява предимствата на предните два подхода;
Сподели с приятели: |