Структурой называется совокупность логически связанных переменных, возможно, различных типов, сгруппированных под одним именем.
Структура в языке С/С++ аналогична по смыслу записи в ТР. Вид ее описания:
struct <имя структуры>
{
тип <имя_поля1>; // Определение структуры
тип <имя_поля2>; // является оператором,
тип <имя_поляN>; // поэтому заканчивается
}; // точкой с запятой.
Определение структуры является оператором, поэтому заканчивается точкой с запятой. Переменные, которые объединяются структурой, называются членами, элементами или полями структуры.
Пример определения структуры STUDENT (сведений о студенте)
struct STUDENT {
сhar Name[30];
char Groupe[5];
int Age;
};
Такая запись не задает никакой переменной и выделения памяти не производится. Под именем STUDENT задаетcя частный вид структуры или шаблон структуры, т.е. определен новый тип struсt STUDENT. Для объявления конкретных переменных этого типа можно написать:
struct <имя структуры> <список переменных>;
Пр. struct STUDENT stud1, stud2;
Переменные также могут задаваться одновременно с шаблоном
struct STUDENT {
сhar Name[30];
char Groupe[5];
int Age;
} stud1, stud2;
Теперь объявлены две переменные и компилятор автоматически выделит под них память (под каждую переменную непрерывный участок).
Внешние статические структуры можно инициировать, помещая следом за определением список начальных значений элементов:
struct stud1="Графкин Е.","В-227",18;
Доступ к элементу поля осуществляется с помощью операции "точка" или "выделения элемента": <имя_переменной_стр>.<имя_поля>
Пример. strcpy(stud2.name, "Петров К.");
Для печати содержимого поля группы элемента структуры запись будет иметь вид: printf(" %c", stud1.Grupe);
Для пятого элемента этого поля – printf("%c",stud1.Grupe[4]);
На практике структурные переменные объединяются в массивы структур. Для объявления массива структур сначала задается шаблон структуры, далее объявляется массив:
struct stud1 sudents[40]; // в памяти создается 30 переменных [0..29].
Если объявлены две переменные типа структур с одним шаблоном, то их можно присваивать друг другу: stud2=stud1;
В этом случае происходит побитовое копирование каждого поля одной структурной переменной в соответствующее поле другой переменной. Переменные типа структуры, описанные под разными именами (даже идентичные) друг другу присваивать нельзя.
Пример: void main() struct St1 m,k;
{struct St1 {int a; struct St2 l;
char b; k . a=1;
}; k . b=’f’;
struct St2 {int a; m=k; // верно
char b; l=k; // неверно
}; l . a=k . a; l . b=k . b; // верно
Переменная типа структура может быть глобальной, локальной или формальным параметром. Любое поле структуры может быть параметром функции func1(int k.a); параметром может является и адрес поля func2(int &k.a).
Можно в качестве формального параметра передать по значению всю структуру, создать указатель на структуру и передать аргумент типа структуры по ссылке. Объявление указателя на структуру имеет вид:
struct <имя структуры> * <имя указателя>;
Например, struct St*uk; // uk – переменная типа указатель на структуру St.
Если передается структура по значению, то все ее элементы заносятся в стек. Если она содержит в качестве своего элемента массив, стек может переполниться. Поэтому рекомендуется использовать ссылки. При передаче по ссылке в стек заносится только адрес структуры, при этом копирование структуры не происходит, а так же появляется возможность менять содержимое элементов.
Указателю можно присвоить адрес переменной uk=&m.
Для получения значения поля а переменной m используется операция доступа к полю:
(*uk).a или uk->a;
Структура операции доступа к полю по указателю
переменная_указатель -> имя_поля; ( перем_указ -> элемент_структуры;)
Операция "стрелка" употребляется, когда необходимо использовать значение элемента структуры с применением переменной-указателя.
В качестве элементов структуры можно использовать массивы, другие структуры, и массивы структур. Например:
struct Adr сhar
{ city[30];
int ind;
char adres[40];
};
struct STUDadr сhar Name[30];
{ struct Adr addr;
char groupe[6]; } st1, st2;
Adr-шаблон структуры, определеный перед объявлением структуры STUDadr. Для присвоения значения элементу ind структуры STUDadr значения надо записать: st1.addr.ind=50.
4.5.3. Поля битов
В отличие от других языков программирования Си обеспечивает доступ к одному или нескольким битам в байте или слове. Если переменные принимают только два значения (например, логические) можно использовать один бит. Такие переменные называют флагами.
Доступ к биту обеспечивают поля битов (bit fields) – это специальный тип членов структуры, в котором определено, из скольких битов состоит каждый элемент. Полем считается последовательность соседних двоичных разрядов в числе типа int или unsigned (signed). Оно объявляется как элемент структуры.
Основная форма объявления структуры битовых полей
struct < имя структуры >
{ <тип имя 1>: <ширина>;
¼
<тип имя N>: <ширина>;
};
где <ширина> – целое число от одного до 16; <тип> – int или unsigned. <Имя> может отсутствовать, тогда отведенные биты не используются (пропускаются). Длина структуры всегда кратна восьми.
Пример 1. Для переменной obj будет выделено восемь бит, но используется только первый.
struct onebit
{ unsigned b: 1;
}obj;
Пример 2.
struct М{ // значения диапазонов полей
int а:4; // а[-8, 7]
int b:1; // b[- 1, 0]
unsigned с:5; // с[0,31]
int :2; // пусто
int d :2; // d[-2,1]
unsigned е :2 } // е[0,3]
Расположение полей в структуре М из 16 бит получится следующее
А
| b
| с
| не используется
| d
| е
|
0 … 3
|
| 5 … 9
| 10 11
| 12 13
| 14 15
|
Операции для полей битов такие же, как и для структур:
Присваивание. Пусть struct М byte; то byte.а=3;
byte.b=0;
Доступ к полю (точка) byte.с=30;
Не допускаются массивы полей битов, указатели на поля битов и функции, возвращающие поля битов. К битовым полям не может применяться операция «&» (адрес).
Обычно поля битов используются, когда необходимо установить несколько объектов (полей структуры) в одно машинное слово.
В структуре могут быть смешаны обычные переменные и поля битов. Поля битов не могут располагаться на пересечении границ объявленных для них типов (они располагаются в оставшемся пространстве предыдущего поля или начиная с новой целой границы).
Безымянное поле используется только как заполнитель. Для принудительного выравнивания к границе следующего целого числа используется специальный размер Æ
struct { int f1:1
int : 2;
int f2:1;
:Æ; stb.f3 заполняется в следующем int.
int f3:1 ;
} stb;