Текст опубликован в личном блоге и его автор не имеет отношения к администрации сайта
struct имя_шаблона {тип_1 имя_поля_1;
тип_2 имя_поля_2;
•••
тип_N имя_поля_N;};
где имя_шаблона – имя шаблона, удовлетворяющее правилам задания идентификаторов языка Си;
struct BOOK { char name [20];
char title[44];
int year; float price; };
Имена полей в одном шаблоне должны быть уникальными. Однако в разных шаблонах можно использовать совпадающие имена полей. Кроме того, имена шаблонов проверяются на уникальность друг с другом, а не с метками или именами переменных. Раз так, то имя шаблона может и совпадать с именами полей, переменных или метками.
struct BOOK first_book;
Здесь описывается структурная переменная по приведенному ранее шаблону BOOK. Компилятор выделит под переменную число байтов памяти, достаточное для хранения всех ее полей. В данном случае это 70 байт. Число байтов, выделенное под структурную переменную, не всегда равно сумме длин отдельных полей из-за влияния дополнительного фактора внутреннего представления структурных переменных, называемого выравниванием. Точно выделенное число байтов всегда возвращает операция sizeof (struct имя_шаблона). Например, sizeof (struct BOOK) возвратит всегда 70, однако для других шаблонов возможны варианты.
struct BOOK { char name[20];
char title[44];
int year; float price;
} first_book, child_book, dog_book;
Для структурных переменных действуют правила видимости и времени жизни.
first_book.year=1992;
dog_book.year=first_bookyear;
strcpy( child_book.title, "Белый Бим Черное Ухо");
scanf("%f', &first_book.price);
Ссылка на поле структурной переменной обладает всеми свойствами обычных переменных. Если поле – это массив символов, то например child_book.title – это указатель-константа на первый элемент массива. Можно определить адрес первого байта поля структурной переменной обычной операцией взятия адреса. Например, &first_book.price – это адрес первого байта поля. Естественно, что ссылка на поле структурной переменной может располагаться как слева, так и справа от операции присваивания. Так же, как и для обычных операндов, действуют правила преобразования типов при смешивании операндов разных типов.
first_book=chitd_book;
first_book=child_book=dog_book;
Операция присваивания структурных переменных приводит к физической пересылке в памяти числа байтов, равного размеру шаблона структурной переменной. В приведенном примере три структурные переменные будут иметь поля, совпадающие с полями структурной переменной dog_book.
struct BOOK { char name[20];
char title[44];
int year; float price; };
struct BOOK first_book=
{"Митчелл М",
"Унесенные ветром”,
1991. 5.25 },
child_book = { "Троепольскчй Г.Н.",
"Белый Бим Черное Ухо",
1980,2.78},
dog_book = {"Михайлов О.С",
"Воспитание щенка",
1968.0.47};
Разрешается объединять задание шаблона, описание структурных переменных и их инициализацию в одном предложении языка Си.
typedef struct BOOK { char name[20];
char title[44];
int year; float price;
} MY_BOOKS;
Затем можно использовать сконструированный тип для описания необходимых данных, например так:
typedef struct {char nате[20];
char title[44];
int year; float price;
}BOOKS;
typedef struct {char class, subclass;
int number;
} MY_UDC;
struct UDC {char class, subclass;
tnt number;};
struct BOOK{ struct UDC udk_clcss;
char name [20];
char title[44];
int year; float price; } first_book, child_book, dog_book;
В данном примере описывается шаблон структуры, имеющей вложенную структуру, и три структурные переменных по шаблону BOOK, т. е. и для вложенных структур действуют те же правила описания полей: задается шаблон (в данном примере это struct UDC) и имя поля (в шаблоне BOOK это udk_dass).
first_book.udc_class.class = 'А';
dog_book.udc_class.number = 681;
Единственное ограничение на вложение структур состоит в том, что структура не может вкладываться сама в себя, т. е. некорректным, например, будет следующее выражение:
struct BOOK { struct BOOK my_own; /* это ошибка */
char name [20];
char title[44];
int year; float price; };
Отметим, что разрешается использовать описываемый шаблон, если одно из полей является указателем на описываемую структуру. Например, будет корректным такое описание:
struct BOOK {
struct BOOK * my_own; /* это разрешается */
char name f 20J;
char title[44];
int year, floatprice; };
struct UDC {char class, subclass;
int number; };
struct BOOK{ struct UDC udc_class;
char name[20];
char title[44];
int year; float price; };
struct BOOK * ptr_book, first_book;
ptr_book = &first_book;
ptr_book -> year = 1992;
ptr_book -> udc_class.class = 'A';
ptr_book -> udc_class.number = 681;
strcpy(ptr_book -> title, "Белый Бим Черное Ухо”);
scanf(“%f, & ptr_book -> price);
Ссылка на поле структурной переменной через указатель обладает всеми свойствами обычной переменной. Например, если поле – это массив, символов, то ptr_book -> title – это указатель-константа на первый элемент массива. Можно определить адрес первого байта поля структурной переменной обычной операцией взятия адреса. Например, &ptr_book -> price – это адрес первого байта поля. Естественно, что ссылка на поле структурной переменной через указатель может располагаться как слева, так и справа от знака операции присваивания. Вообще говоря, ссылка на поле через указатель – это синоним ссылки на это поле через операцию *. Например, если описан шаблон BOOK и сделано описание данных
struct BOOK* ptr_book,flrst_book;
ptr_book = &first_book:
то ссылка (*ptr).year эквивалентна ссылке
first_book.year и ссылке ptr-> year.
Заслуживает внимания то, как осуществляется доступ к полям вложенной структуры. Например, для того чтобы сослаться на поле class вложенной переменной по шаблону struct UDC, сначала используют операцию ->, а затем ссылку на поле вложенной структуры операцией '.':
ptr_book -> udc_class.class = 'A;
Используя указатель на структурную переменную, можно сделать ссылку на поле любого типа, в том числе, например, и на указатель. Отметим, что указатель на структуру может использоваться до объявления шаблона структуры, так как компилятору не требуется информация о размере структуры, а размер самого указателя известен. Далее приведен пример доступа к полям структуры с использованием указателя на структуру UDC, являющегося полем структуры BOOK:
struct BOOK{struct UDC * udc_class; /*указатель*/
char name [20];
char title [44];
int year; float price; };
struct UDC {char class, subclass;
int number; } my_class;
struct BOOK * ptr_book, first_book;
ptr_book = & first_book;
ptr_book -> udc_class = & my_class;
ptr_book -> year = 1992;
ptr_book -> udc_class -> class = 'A';
ptr_book -> udc_class -> number = 681;
strcpy( ptr book -> title, ”Белый Бum Черное Ухо” );
scanf("%f”, & ptr_book -> price);
В приведенном примере структурная переменная first_book, созданная по шаблону struct BOOK, включает поле udc_class. Оно представляет собой указатель на структурную переменную по шаблону struct UDC. Сам шаблон struct UDC описан после описания указателя udc_class. Операция присваивания
ptr_book -> udc_class = & my_class;
записывает в поле udc_class адрес первого байта структурной переменной my_class. После этого можно ссылаться на поля переменной udc_dass через указатель ptr_book, например, так:
ptr_book -> udc_class -> class = 'А';
typedef struct {char name[20];
char title [44];
int year; float price; } BOOKS:
BOOKS library [25];
Доступ к элементам массива может выполняться с использованием индекса или через указатель-константу, которым является имя массива. Например, так можно выполнить доступ к полю year i-ro элемента:
library [i].year = 28; или
(*( library +i)).year=28; или
(library + i) -> year = 28;
BOOKS library[25], *ptr= library;
то для доступа к полям i-ro элемента массива структурных переменных можно использовать указатель ptr:
(ptr+i)->year=28;
Продвижение указателя ptr операцией ++ или - - соответственно увеличивает или уменьшает его на размер типа BOOKS, т. е. устанавливает на следующий элемент массива структурных переменных вперед или назад. Это удобно при последовательном доступе к элементам массива.
struct EXAMPLE { int i:1;
unsigned j: 2;
int :3;
int k:2;
} my_struct;
При ссылке на поле в выражениях по маске выделяются нужные биты и при необходимости выполняется сдвиг числа вправо. В результате оно вступает в операцию в соответствии с типом как число со знаком или без него. При ссылке на битовое поле слева от операции присваивания выполняется обратная операция: сдвиг числа вправо, выделение по маске нужных битов и размещение их в структурной переменной поразрядной логической операцией с предыдущим содержимым поля.
enum [ имя_шаблона ] { имя_1 [ константа_1], имя_2 [константа_2 ]...};
где имя_шаблона – необязательное имя конструируемого типа;
enum days {monday=1, tuesday, wednesday,
thurday, friday, saturday, sunday
} week_day, anyday;
Здесь описываются две переменные-перечисления week_day и anyday по шаблону, имя которого days. Используя директиву typedef, можно сократить время на описание новых переменных. Например:
typedef епит { monday = 1, tuesday, wednesday,
thurday, friday, saturday, sunday
} DAYS;
DAYS week_day, anyday;
Переменной-перечислению могут присваиваться только значения, задаваемые перечисляемыми константами. Значения перечисляемым константам задаются либо явной инициализацией, либо в случае ее отсутствия – по умолчанию. В случае отсутствия явных инициализаторов первой перечисляемой константе ставится в соответствие значение 0, а каждая следующая перечисляемая константа принимается на единицу большей, чем предыдущая. Таким образом, в приведенном выше примере перечисления DAYS символическая константа monday будет равна 1, a sunday – 7.
DAYS week_day, anyday, * ptr;
week day=monday; /* это правильно */
anyday =1; /* ошибка, несмотря на то, что Monday==1 */
ptr=&week_day; /* правильная инициализация указателя */
*ptr=friday; /* правильное использование указателя */
monday=4; /* ошибка, так как monday - это константа */