- •Функции.
- •Вызов функции с переменным числом параметров
- •Функция main и её параметры.
- •Директивы препроцессора (прекомпилера).
- •Объявление указателей.
- •Модификатор const.
- •Операции.
- •Указатели на различные типы.
- •Указатель на void.
- •Применение указателей для передачи данных между функциями.
- •Массивы.
- •Индексация массивов.
- •Хранение массива в памяти. Адреса элементов. Хранение массива в памяти.
- •Массивы и константные указатели.
- •Статическое и динамическое выделение памяти.
- •Функции calloc, malloc, free
- •Функция realloc
- •Передача массивов в качестве аргументов функции.
- •Указатели на функции.
- •Библиотеки функций.
- •Функции форматированного ввода-вывода.
- •Функция printf().
- •%[Флаги] [Ширина] [.Точность] [{h | l | I | i32 | i64}]тип
- •Для чего нужен форматированный вывод.
- •Функция scanf().
- •Функции sprintf() и sscanf().
- •Функции fprintf() и fscanf().
- •Функции неформатированного ввода-вывода.
- •Работа со строковыми данными (стрингами). Представление строковых данных в языке c.
- •Функции работы со строками.
- •Потоковый ввод-вывод
- •Функции форматированного ввода-вывода.
- •Функция printf().
- •%[Флаги] [Ширина] [.Точность] [{h | l | I | i32 | i64}]тип
- •Для чего нужен форматированный вывод.
- •Функция scanf().
- •Функции sprintf() и sscanf().
- •Функции fprintf() и fscanf().
- •Функции неформатированного ввода-вывода.
- •Функции работы с файлами.
- •Потоковый ввод-вывод
- •Работа с потоками
- •Курсор.
- •Ввод-вывод отдельных символов и строк.
- •Форматированный ввод-вывод информации в файл.
- •Блочный потоковый ввод-вывод
- •Смена текущей позиции в файле. Проверка конца файла.
- •Функции доступа к файлам нижнего уровня.
- •Методы сортировки данных.
- •Введение
- •Сравнение методов сортировки
- •Программная реализация алгоритмов сортировки
- •Метод пузырька.
- •Метод обмена.
- •Метод вставки.
- •Метод Шелла.
- •Метод кучи (бинарной кучи).
- •Очередь
- •Линейный список
- •Физическое (машинное) представление линейных списков
- •Программные реализации структур данных. Стек. Реализация в виде массива.
- •Стек. Связанное представление.
- •Очереди. Реализация в виде массива.
- •Дерево. Связанное представление.
- •Рекурсивный вызов функций.
- •Структуры. Объединения. Перечисления.
- •Перечисление (enum).
- •Производные типы данных.
- •Структура (struct).
- •Побитовое описание полей структуры.
- •Объявление переменных, реализующих структуру.
- •Доступ к элементам структуры.
- •Объединение (union).
- •Вложенное описание структур и объединений.
- •Описание структур и объединений в виде пользовательского типа.
- •Передача структур и объединений в виде параметров функции.
- •Инициализация структур и объединений.
- •Выгода от использования структур
Производные типы данных.
К производным (сложным) типам данных в языке C относятся структуры и объединения. Эти типы данных позволяют описывать большие объёмы данных в структурированном (упорядоченном) виде.
Структуры и объединения представляют широкие возможности для структурированного хранения данных и являются первым шагом к объектно-ориентированному программированию и классам. Один из принципов хорошего тона программирования гласит, что все логически связанные между собой данные (особенно глобальные и часто передаваемые между функциями) по возможности должны быть структурированы и хранимы в виде структур, а не в виде отдельных переменных. Способ структурированного описания данных и методика применения производных типов описана ниже.
Структура (struct).
Структура является производным (сложным) типом данных, представляющим собой последовательно хранящийся в памяти набор переменных. Синтаксис определения структуры выглядит следующим образом:
struct ИмяСтруктуры
{
тип элемент1;
тип элемент2;
}ИмяПеременной;
где ИмяСтруктуры – некоторый идентификатор структуры,
ИмяПеременной – имя создаваемой переменной.
Внутри фигурных скобок находится список переменных – элементов (членов) структуры, разделённых точкой с запятой. Аналогично синтаксису определения перечисления, ИмяСтруктуры и ИмяПеременной могут быть опущены.
Пример:
struct st1
{
int i;
char str[5];
double j;
}var1;
В результате выполнения такого определения будет создана структура с идентификатором st1 и переменная var1 типа структура st1. Её элементы будут размещены в памяти следующим образом:
Адрес начала переменной var1( = &var1)
↓
B0 |
B1 |
B2 |
B3 |
B4 |
B5 |
B6 |
B7 |
B8 |
B9 |
B10 |
B11 |
B12 |
B13 |
B14 |
B15 |
B16 |
|
int i; |
char str[5]; |
double j; |
На самом деле, точно такое представление в памяти будет только в том случае, если выключить автоматическое выравнивание структур (с помощью директивы препроцессора #pragma pack(0)).
Дело в том, что современные процессоры быстрее оперируют в блоками данных длиной в несколько байт (обычно 8), поэтому в современных компиляторах по умолчанию включено автоматическое выравнивание структур, дополняющее каждый элемент структуры таким количеством байт, что его длина становится кратной восьми.
Поэтому, при включенном автоматическом выравнивании структур, все её элементы будут дополнены ничего не значащими (пустыми) байтами до длины в восемь байт.
Структуры являются очень мощным инструментом, позволяющим оптимизировать хранение и обработку больших объёмов данных. Но не стоит перебарщивать и связывать в структуры переменные совершенно не связанные между собой логически. Например, не стоит связывать в структуру две независимые переменные i и j, являющиеся отдельно используемыми счётчиками. В то же время две переменных x и y, описывающие координаты какой-либо точки можно и нужно связать в структуру Point и использовать далее как элементы этой структуры.