|
Структуры, объединения, перечисления
Структуры Структура это составной объект языка Си, представляющий собой совокупность логически связанных данных различного типа, объединенных в группу под одним идентификатором (ID). Данные, входящие в эту группу называют полями. Термин «структура» в языке Си соответствует двум разным по смыслу понятиям: - структура – это обозначение участка оперативной памяти, где располагаются конкретные значения данных. В дальнейшем – это структурная переменная, поля которой располагаются в смежных областях ОП. - структура – это правила формирования структурной переменной, которыми руководствуется компилятор при выделении ей места в ОП и организации доступа к ее полям. Определение объектов типа структуры производится за два шага: - декларация структурного типа данных, не приводящая к выделению участка памяти; - определение структурных переменных с выделением для них памяти.
Декларация структурного типа данных Структурный тип данных задается в виде шаблона, общий формат описания которого следующий: 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:
Структурный тип данных удобно применять для групповой обработки логически связанных объектов. Параметрами таких операций являются адрес и размер структуры. Примеры групповых операций: - захват и освобождение памяти для объекта; - запись и чтение данных, хранящихся на внешних носителях как физические и/или логические записи с известной структурой (при работе с файлами). Т.к. одним из параметров групповой обработки структурных объектов является размер, не рекомендуется декларировать поле структуры указателем на объект переменной размерности, т.к. в данном случае многие операции со структурными данными будут не корректны, например struct Stud_type { char *Number, *fio; double S_b; }; в данном случае, вводя строки Number и fio различной длины, размеры объектов будут также различны.
Создание структурных переменных Как уже отмечалось само описание структуры не приводит к выделению под нее места в ОП. Теперь необходимо создать нужное количество переменных с приведенной структурой и сделать это можно двумя способами. Способ 1. В любом месте программы для декларации структурных переменных, массивов, функций и т.д., используется объявленный в шаблоне структурный тип, например: struct Stud_type student; - структурная переменная; Stud_type Stud[100]; - массив структур Stud_type *p_stud; - указатель на структуру Stud_type* Fun(Stud_type); - прототип функции с параметром структурного типа, возвращающей указатель на объект структурного типа. Способ 2: в шаблоне структуры между закрывающейся фигурной скобкой и символом «;» указывают через запятые идентификаторы структурных данных. Для нашего примера, используя, можно записать: struct Stud_type { char Number[10], Fio[40]; double S_b; } student, Stud[100], *p_stud; Если дальше в программе не понадобится вводить новые данные объявленного структурного типа, «Stud_type» можно не указывать. При декларации структурных переменных возможна их одновременная инициализация Например: struct Stud_type { char Number[10], Fio[40]; double S_b; } student = {“123456”, “Иванов И.И.”, 6.53 }; или: Stud_Type stud1 = {“123456”, “Иванов И.И.” }; Отметим, что если список инициализации будет короче, то оставшиеся поля структурной переменной будут заполнены нулями.
Некоторые особенности: 1) поля структуры, как правило, имеют разный тип кроме функций, файлов и самой этой структуры; 2) поля не могут иметь атрибут, указывающий «класс памяти», данный атрибут можно определить только для всей структуры; 3) идентификаторы (ID), как самой структуры, так и ее полей могут совпадать с ID других объектов программы, т.к. шаблон структуры обладает собственным пространством имен; 4) при наличии в программе функций пользователя шаблон структуры рекомендуется поместить глобально перед определениями всех функций и в этом случае он будет доступен всем функциям. Элементы структур в общем случае размещаются в памяти последовательно с учетом выравнивания начальных адресов. Выравнивание - установка значения адреса, кратного некоторой величине, определяемой особенностями адресации данных на аппаратном уровне. Часто выравнивание не обязательно, но при этом скорость обращению к объекту может снижаться.
Обращение к полям структур производится при помощи составных имен, которые образуются двумя способами: а) использованием операции принадлежности (.) в виде: ID_структуры. ID_поля или (*указатель_структуры).ID_поля б) при помощи операции косвенной адресации (->) в виде: указатель_структуры -> ID_поля или (& ID_структуры) ->ID_поля
Примеры обращения для объявленного ранее шаблона: 1). Stud_Type s1, s2; Обратиться к полям элемента объявленной структуры s1: s1. Number, s1. Fio, s1. S_b; 2). Stud_Type *s1, *s2; Обратиться к полям элемента объявленной структуры s1: s1 -> Number, s1 -> Fio, s1 -> S_b; Так как структурная переменная является сложным объектом, операции, например, присваивания для таких переменных необходимо производить при помощи стандартных функций. Пусть необходимо содержимое структурной переменной s2 присвоить s1: Stud_Type s1, s2; Идентификатор структурной переменной является константным указателем на начало размещения данного объекта в ОП, поэтому, в выражении s1 = s2; допущена ошибка, т.к. в левой части - константа. Правильное присваивание: memcpy(&s1,&s2,sizeof(Stud_Type)); или Stud_Type *s1, s2; s1 = s2; Участок программы, иллюстрирующий передачу структурных данных в функцию: struct Spisok { char Fio[20]; float S_Bal; }; // Описание прототипов void Out(Spisok); void Vvod(int, Spisok *); void main(void) { Spisok Stud[50], *sved; ... for(i=0;i<N;i++) Vvod(i, &Stud[i]); puts("\n Spisok Students"); for(i=0;i<N;i++) Out(Stud[i]); ... }
void Out(Spisok dan) { printf("\n %20s %4.2f",dan.Fio, dan.S_Bal); }
void Vvod(int nom, Spisok *sved) { printf("\n Введи сведения %d: ",nom+1); fflush(stdin); puts("\n ФИО - "); gets(sved->Fio); puts("\n Средний балл - "); scanf(“%f”, &sved->S_Bal); } Вложенные структуры Структуры могут быть вложенными, т.е. поле структуры может связующим полем с внутренней структурой, описание которой должно предшествовать по отношению к основному шаблону. Например, в структуре person, содержащей сведения - Ф.И.О., дата рождения, сделать дату рождения внутренней структурой date по отношению к структуре person. Тогда шаблон такой конструкции будет выглядеть так: struct date { int day, month, year; }; struct person { char fio[40]; struct date f1; }; Объявляем переменную и указатель на переменные такой структуры: struct person a, *p; Инициализируем указатель p адресом переменной а: p = &a; Тогда, обращение к полям структурной переменной a будет выглядеть следующим образом: a. fio a. f1. day a. f1. month a. f1. year или p -> fio p -> f1. day p -> f1. month p -> f1. year Можно в качестве связи с вложенной структурой использовать указатель на нее: struct date { int day, month, year; }; struct person { char fio[40]; struct date *f1; }; Тогда обращение к полям будет следующим: a. fio a. f1 -> day a. f1 -> month a. f1 -> year или p -> fio p -> f1 -> day p -> f1 -> month p -> f1 -> year Использование средства typedef упрощает определение структурных переменных, так как отпадает необходимость при их декларации указывать ключевое слово stuct. Например: typedef struct person { char fio[40]; int day, month, year; } W; здесь W - созданный пользователем тип данных - «структура с указанными полями» и для нашего примера: W t1, t2; - декларация двух переменных типа W, а это значит, что можно на такие переменные устанавливать указатели и использовать косвенную адресацию. Массивы структур Структурный тип "struct ID_структуры" как правило используют для декларации массивов, элементами которых являются структурные переменные. Это позволяет создавать программы, оперирующие с "примитивными базами данных". Например: struct person spisok[100]; // spisok - массив структур Или можно записать так: struct person { char fio[40]; int day, month, year; } spisok[100]; В данном случае обращение к полю, например, day i -той записи может быть выполнено одним из следующих способов: spisok[i]. day=22; *(spisok+i). day=22; (spisok+i) -> day=22;
ЧТО ПРОИСХОДИТ ВО ВЗРОСЛОЙ ЖИЗНИ? Если вы все еще «неправильно» связаны с матерью, вы избегаете отделения и независимого взрослого существования... ЧТО ТАКОЕ УВЕРЕННОЕ ПОВЕДЕНИЕ В МЕЖЛИЧНОСТНЫХ ОТНОШЕНИЯХ? Исторически существует три основных модели различий, существующих между... Система охраняемых территорий в США Изучение особо охраняемых природных территорий(ООПТ) США представляет особый интерес по многим причинам... Что делает отдел по эксплуатации и сопровождению ИС? Отвечает за сохранность данных (расписания копирования, копирование и пр.)... Не нашли то, что искали? Воспользуйтесь поиском гугл на сайте:
|