
- •13. Функции пользователя и классы памяти.
- •13.1. Сущность и предназначение функций.
- •13.2. Определение и вызов функции.
- •13.3. Прототип функции.
- •13.4. Область видимости.
- •13.5. Классы памяти объектов в языке Cи.
- •13.6. Разбиение программы на модули.
- •14. Структуры и объединения
- •14.1. Понятие структуры
- •14.2. Декларация структурного типа данных
- •14.3. Объявление структурных переменных
- •14.4. Обращение к полям структуры
- •14.5. Операции со структурой как единым целым
- •14.6. Вложенные структуры
- •14.7. Массивы структур
- •14.8. Размещение структурных переменных в памяти
- •14.9. Битовые поля
- •14.10. Объединения
- •15. Генерация псевдослучайных чисел.
- •16. Файлы в языке с
- •16.1. Типы файлов.
- •16.2. Открытие файла
- •16.3. Закрытие файла
- •16.4. Запись - чтение информации
- •А) Посимвольный ввод-вывод
- •Б) Построчный и форматированный ввод-вывод
- •В) Блоковый ввод-вывод
- •Int fflush(file *stream);
- •16.5. Текстовые файлы
- •16.6. Перенаправление стандартного ввода-вывода
- •16.7. Бинарные файлы
- •16.8. Дополнительные полезные функции
- •16.9. Простейший пример создания собственной базы данных
13.6. Разбиение программы на модули.
Разбиение программы на модули (отдельные файлы с текстом программы) позволяет использовать готовые модули в разных программах, а также является важнейшим способом разделения труда при работе в коллективе.
При таком разбиении в одних модулях должны содержаться функции, а в других - их вызовы. Модули должны быть объединены в единый проект, включающий головной файл (например, Project1) и отдельные модули (например, Unit1 и Unit2).
Существуют разные способы взаимосвязи модулей в проекте. Одни из них основаны на директиве #include (см. ниже тему "Препроцессор"). Другие - на описании extern:
Пример 2. Разбиение программы на модули с использованием класса памяти extern:
Основной файл проекта |
Дополнительный файл |
int x, y; char str[ ] = “Rezult = ”; void fun1(void); void fun2(void); void fun3(void); void main(void){ fun1(); fun2(); fun3(); } void fun1(void) { y = 15; printf(“\n %s %d\n”, str, y); } |
extern int x, y; extern char str[ ]; int r = 4;
void fun2(void) { x = y / 5 + r; printf(“ %s %d\n”, str, x); } void fun3(void) { int z= x + y; printf(“ %s %d\n”, str, z); }
|
14. Структуры и объединения
В реальных задачах информация, которую требуется обрабатывать, может иметь достаточно сложную структуру. Для ее адекватного представления используются типы данных, построенные на основе базовых типов данных, массивов и указателей. Языки высокого уровня позволяют программисту определять свои типы данных и правила работы с ними, т.е. типы, определяемые пользователем. В языке Си к ним относятся структуры, объединения и перечисления. Рассмотрим их более подробно.
14.1. Понятие структуры
Структура – это составной объект языка Си, представляющий собой совокупность логически связанных данных различных типов, объединенных в группу под одним идентификатором. Данные, входящие в эту группу, называют полями.
Определение объектов типа структуры производится за два шага:
– декларация структурного типа данных, не приводящая к выделению участка памяти;
– определение структурных переменных объявленного структурного типа с выделением для них памяти.
14.2. Декларация структурного типа данных
Структурный тип данных задается в виде шаблона, общий формат описания которого следующий:
struct ID структурного типа {
описание полей
};
Атрибут «ID структурного типа», т.е. ее идентификатор является необязательным и может отсутствовать.
Описание полей производится обычным способом: указываются типы и идентификаторы.
Пример определения структурного типа:
Необходимо создать шаблон, описывающий информацию о студенте: номер группы, ФИО и средний балл. Один из возможных вариантов:
struct Stud_type {
char Number[10];
char Fio[40];
double S_b;
};
Поля одного типа при описании можно объединять в одну группу:
struct Stud_type {
char Number[10], Fio[40];
double S_b;
};
Размещение данного объекта типа Stud_type в ОП схематически будет выглядеть следующим образом:
-
Number
Fio
S_b
10
40
8
длина в байтах
Структурный тип данных удобно применять для групповой обработки логически связанных объектов.
Иногда параметрами таких операций могут выступать адрес и размер (либо тип) структуры. Примеры подобных групповых операций:
- захват и освобождение памяти для объекта;
- запись и чтение данных, хранящихся на внешних носителях как физические и/или логические записи с известной структурой (при работе с файлами).
Т.к. одним из параметров групповой обработки структурных объектов является размер, нужно быть осторожным, если декларировать поле структуры как объект переменной размерности (например, как тип String), т.к. в этом случае "переменная" его часть будет храниться отдельно от остальной структуры, и некоторые операции со структурными данными будут не корректны, например:
struct Stud1 {
String Number, fio;
double S_b;
};
Хотя само такое определение структуры вполне допустимо, но не все операции со структурами, описанные ниже (например, запись целой структуры в файл), в применении к нему дадут верный результат.
Некоторые особенности:
1) поля структуры, как правило, имеют разный тип, кроме функций, файлов и самой этой структуры;
2) поля не могут иметь атрибут, указывающий «класс памяти», данный атрибут можно определить только для всей структуры;
3) идентификаторы (ID) как самой структуры, так и ее полей могут совпадать с ID других объектов программы, т.к. шаблон структуры обладает собственным пространством имен;
4) при наличии в программе функций пользователя шаблон структуры рекомендуется поместить глобально перед определениями всех функций, и в этом случае он будет доступен всем функциям.