Несколько переменных, описывающих разные свойства одного объекта предметной области можно объединить в структуру.
Каждый элемент структуры имеет уникальное имя. В отличие от массива элементы структуры могут иметь разные типы.
В языке C структуру сначала рекомендуется определить как тип и только после этого определять наборы такого типа:
В C++\
`tt"struct" quad "имя" { "тип"_1 quad "элемент"_1; quad "тип"_2 quad "элемент"_2; quad ...};`\
определяет тип с тем же именем. При использовании такого определения в C вместо простого имени придется указывать ``struct `` `"имя"`.
``typedef`` часто используется для сокращения названия типа из нескольких слов:
```c
typedef unsigned long long ull;
typedef unsigned char byte;
ull a; // unsigned long long a;
byte b; // unsigned char b;
```
Для доступа к элементам структуры (*полям*) используется операция ``.``: `"имя_структуры" tt"." "имя_поля"`
Список начальных значений для набора-структуры указывается в ``{}`` через запятую. Можно явно указать, какому полю присваивается значение: ` tt"." "имя_поля" ="выражение"`. Если значение какого-либо поля явно не указано, то оно получает значение 0.
Примеры структур:
```c
typedef struct { double x, y, z; } coord; // координаты в пространстве
typedef struct { // дата
char day; // день 1-31
char month; // месяц 1-12
int year; // год
} date;
typedef struct { // информация о человеке
char name[51]; // имя
date birthday; // дата рождения
char addr[101]; // адрес
char job[16]; // должность
int salary; // зарплата
} person;
```
Примеры определения и инициализации наборов-структур:
```c
coord p1={1, 7, 2.5};
date d1;
person joe={"Joseph",{20,11,1942},"Washigton, DC","President",100000};
person team[5]= // массив лиц
{ {"Kamala", .job="Vice-president",.salary=150000},
{"Antony", .job="Secretary"}
};
```
В отличие от массивов структуры можно копировать целиком обычным присваиванием, в том числе в случаях, когда одним из полей является массив. Для копирования отдельного поля-массива нужно использовать ``memcpy`` или ``strcpy``. Вместо присваивания полям значений по отдельности можно присвоить структуру-значение: `("спецификаторы" quad "тип") {"список_значений_для_полей"}`
```c
d1=joe.birthday; // копируем все поля
team[4]=joe; // копируем все поля
team[3]=team[2]; // копируем все поля
strcpy(team[3].addr,joe.addr); // но копируем одно поле-строку
joe.birthday=(date){30,4,1945}; // присваивание структуры-значения вместо joe.birthday.day=30; joe.birthday.month=4; ...
team[4]=(person){"Karine", {12,8,1974}, .job="Press Secretary"};
```
Когда структура является частью другой структуры и не используется отдельно, можно не вводить тип:
```c
typedef struct {
char name[51]; // имя
struct { char day, month; int year; } birthday; // дата рождения
int salary; // зарплата
} person;
...
person p;
p.birthday.day=11;
```
Структуры можно использовать для упаковки нескольких небольших чисел в машинное слово:
```run-c
#include <stdio.h>
#include <stdbool.h>
typedef struct {
int a:4; // число от -8 до 7
bool flag:1; // 0 или 1
unsigned b:10; // число от 0 до 1023
// +1 бит так как тип short требует выравнивание на 2 байта
short c; // попробуйте изменить на int
} packed;
typedef struct { // то же без упаковки
int a; // 4 байта
bool flag; // 1 байт +3 байта для выравнивание на 4 байта
unsigned b; // 4 байта
short c; // 2 байта +2 байта для выравнивание на 4 байта
} unpacked;
int main() {
packed x;
unpacked y;
printf("%d %d\n",sizeof(x),sizeof(y)); // 4 16
}
```