- •Функции.
- •Вызов функции с переменным числом параметров
- •Функция 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 допускается многоуровневое вложенное описание структур и объединений. В ряде случаев это имеет огромное практическое значение. Например, с помощью следующего описания можно легко разбить число типа int на 4 составляющих его байта:
union unIntParts
{
int iNum;
struct
{
unsigned char Byte0;
unsigned char Byte1;
unsigned char Byte2;
unsigned char Byte3;
}Bytes;
}IntParts;
Допустим, что в программе необходимо считать и распечатать 4 байта некоторого числа x типа int по-отдельности. Осуществить это можно следующим образом:
void PrintBytes(int x)
{
IntParts.iNum=x;
printf("Byte 0 =%d", IntParts.Bytes.Byte0);
printf("Byte 1 =%d", IntParts.Bytes.Byte1);
printf("Byte 2 =%d", IntParts.Bytes.Byte2);
printf("Byte 3 =%d", IntParts.Bytes.Byte3);
}
Замечу, что идентификатор Bytes в описании структуры можно было опустить. В этом случае элементы Byte0…Byte3 находились бы не на третьем, а на втором уровне вложения и доступ к ним осуществлялся бы с помощью записи IntParts.Byte0, т.е., например:
printf("Byte 0 =%d", IntParts.Byte0);
Другое применение вложенных описаний структур и объединений – для описания сложных данных с полями различных типов.
Например, пусть программа описывает набор населённых пунктов. У каждого из них есть набор одинаковых параметров: название (Name), численность населения (Population) и тип населённого пункта (Type), который может быть равен 0 (город), 1 (посёлок), 2 (деревня).
А вот далее для каждого населённого пункта должен быть описан свой набор параметров (разумеется, они условны и приведены только для примера):
пусть для города - Площадь (Area) и названия районов (Districts)
для посёлка - название области (Region) и название центральной улицы (MainStreet)
для деревни – количество колхозников (Villagers) и количество фермеров (Farmers)
Это довольно сложное описание хранимых данных может быть реализовано с помощью следующей конструкции:
struct stInfo
{
char Name[255]; // Общие поля
int Population;
int Type;
union // Поля, специфичные для каждого типа
{
struct
{
int Area;
char Districts[10][255];
}City;
struct
{
char Region[255];
char MainStreet [255];
}Town;
struct
{
int Villagers;
int Farmers;
}Village;
};
}Info;
В ходе исполнения, в зависимости от значения поля Type, программа может работать с данными из элементов вложенных структур City, Town, Village. Например, если Type=0, то с помощью конструкции Info.City.Area можно узнать площадь города, а если Type=1, то нужно работать с полями Info.Town.Region и Info.Town.MainStreet. Разумеется, никто не возбраняет доступ и к другим полям вложенных структур, но это будет неправильно по смыслу программы.
В ходе разработки программы, структурированную запись данных можно бесконечно усложнять. Например, массив названий районов Districts можно заменить массивом структур Disctricts, тогда структура City будет выглядеть следующим образом:
struct
{
int Area;
struct stDistricts
{
char Name[255];
int Population;
char Area;
}Districts[10];
}City;