РУҚА
Информатика

Структуры и указатели

3 мин чтенияСложность: Обновлено 30 сентября 2026

Что такое структуры

D
Структура

пользовательский тип данных, объединяющий несколько полей (различных или одинаковых типов) под одним именем. Структуры позволяют группировать связанные данные — например, координаты точки, характеристики студента или параметры файла.

Структура описывает набор именованных полей, у каждого поля есть имя и тип. Поля в памяти располагаются в порядке объявления, но между ними могут появляться выравнивающие байты (padding) — это влияет на итоговый размер структуры.

Практическая ценность структур в том, что они повышают читабельность кода и облегчают передачу связанных данных в функции или сохранение в файлы. Часто структура сопровождается функциями для инициализации, копирования и освобождения ресурсов.

Объявление и инициализация структур

Определение структуры обычно включает ключевное слово, имя типа и тело с перечнем полей. Поля могут быть примитивными типами, массивами, указателями и даже другими структурами. После объявления можно создавать переменные этого типа и инициализировать их значениями.

D
Инициализация структуры

присвоение начальных значений полям структуры при создании или с помощью специальных функций. Инициализация бывает статической (в момент объявления) и динамической (после выделения памяти).

№

Пример на псевдо-C: struct S { int x; float y; }; struct S s = { \(4\), 0.0f } — здесь поле x инициализировано числом \(4\) (типичный размер int в байтах на многих архитектурах), поле y — нулём.

Важно помнить, что конкретные размеры и порядок следования байтов зависят от компилятора и платформы. Выражения типа \(\mathrm{sizeof}(\mathrm{int})\) используются для получения размера типа в байтах и помогают писать переносимый код.

Указатели на структуры

D
Указатель на структуру

переменная, хранящая адрес в памяти, где расположен объект структуры. Указатели облегчают передачу больших структур в функции (передаётся адрес, а не копия) и организуют динамическое выделение объектов.

Операции с указателями на структуры включают разыменование и доступ к полям через оператор стрелки. Разыменование позволяет получить сам объект по адресу (\(*p\)), а запись \(p\!->\!field\) — удобный синтаксис для доступа к полю через указатель.

№

Пример: struct S *p = \(\mathrm{NULL}\); // указатель инициализирован как NULL. После выделения p можно использовать: \(*p\).x = 5; или более компактно: p->x = 5 (\(p\!->\!field\)).

При работе с указателями важно следить за временем жизни объекта, на который они указывают: указатель не должен ссылаться на освобождённую или стековую память после выхода из функции.

Арифметика указателей и массивы структур

Арифметика указателей основана на размере того типа, на который указывает указатель. Если p указывает на первый элемент массива структур, то выражение \(p + 1\) сдвинет указатель на один элемент вперёд, а \(p - 1\) — на один элемент назад. При этом фактический сдвиг в байтах равен размеру элемента.

Размер блока, занимаемого массивом из n элементов типа T, можно оценить выражением \(n\times\mathrm{sizeof}(T)\) — это важно при выделении динамической памяти для массива структур.

№

Пример: struct S arr[10]; Если указатель p = &arr[0], то p + 1 указывает на arr[1]. При реализации это означает сдвиг на \(\mathrm{sizeof}(\mathrm{struct\ S})\) байт, равный размеру одной структуры.

Нельзя выходить за границы массива при инкременте/декременте указателя. Такие ошибки приводят к неопределённому поведению и трудноотлавливаемым багам.

Выравнивание, паддинг и offsetof

Из-за требований выравнивания компилятор может вставлять между полями структуры дополнительные байты (padding). Это делается для ускорения доступа к полям и соблюдения требований аппаратной платформы. Итоговый размер структуры часто больше, чем простая сумма размеров полей.

D
Выравнивание

требование, по которому адрес объекта должен быть кратен некоторому значению (обычно степени двойки), зависящему от типа данных. Выравнивание влияет на расположение полей внутри структуры и на итоговый размер типа.

Чтобы узнать смещение конкретного поля внутри структуры, используют выражения вроде \(\mathrm{offsetof}(S,\,field)\). Это полезно при работе с низкоуровневым кодом и при сериализации данных в бинарный формат.

№

Пример: если у структуры есть поле int, которое выровнено по границе \(4\) байт, то компилятор может вставить padding до следующего поля так, чтобы это выравнивание соблюдалось.

Практические рекомендации и шаблоны использования

При проектировании структур стоит думать о компактности и выравнивании: группируйте поля одного размера вместе, чтобы уменьшить внутренний padding. Если нужна строго упакованная память, применяют атрибуты компилятора, но это может снизить производительность на некоторых архитектурах.

Используйте указатели для динамических структур и для обмена большими объёмами данных между функциями без копирования. Всегда инициализируйте указатели (например, присваивая \(\mathrm{NULL}\)) и проверяйте их перед разыменованием.

№

Пример паттерна: выделить память под массив структур size = \(n\times\mathrm{sizeof}(T)\); проверить успешность выделения памяти; инициализировать каждую структуру; затем по завершении работы освободить память.

Документируйте контракт: кто выделяет, кто освобождает память; какие функции модифицируют структуру; какие поля обязательны для корректной работы — это снизит количество ошибок при командной разработке.