Работа со структурами. Вложенные структуры. Массивы структур
Цель работы
Освоить правила объявления шаблона структуры, определения по заданному шаблону структурной переменной или массива структурных переменных. Изучить способы доступа к полям структурной переменной, в том числе через указатель на эту переменную. Освоить способы обработки массивов структурных переменных.
Задание 1
Предложить структуру для описания указанных в вариантах данных. Организовать заполнение полей структурной переменной введенными с клавиатуры значениями. Использовать два способа доступа к полям структуры: через ссылку, содержащую имя структурной переменной и имя поля, и через указатель.
Варианты структур для выполнения работы:
1. ''Человек'': ФИО; пол; домашний адрес (город, улица, дом, квартира); номер телефона.
2. ''Студент'': ФИО; группа; дата рождения (год, месяц, число); домашний адрес (строкой).
3. ''Владелец автомобиля'': ФИО; автомобиль (марка, цвет, гос. номер); номер авт. прав; отделение регистрации ГИБДД.
4. ''Пациент'': ФИО; год рождения; домашний адрес (почтовый индекс, страна, город, улица, дом, квартира); номер телефона.
5. ''Спортивная команда'': название; город команды; количество игроков; результаты игр (выиграно, проиграно, вничью).
6. ''Покупатель'': ФИО; пол; адрес: (город, улица, номер дома, номер квартиры); номер кредитной карточки.
7. ''Автомобиль'': марка; цвет; номера (номер двигателя; гос. регистрационный номер); год выпуска.
8. ''Фильм'': название; режиссер (фамилия, имя, национальность); год выпуска; жанр.
9. ''Музыкальный товар'': порядковый номер в каталоге; название; исполнитель; количество на складе (mp3, CD, DVD).
10. ''Музыкальный альбом'': название альбома; название группы; количество песен на носителе; выпуск (год выпуска, фирма-производитель, тираж).
Задание 2
Используя выполненное задание 1, сформировать в программе одномерный динамический массив структур, организовать заполнение элементов массива с клавиатуры, при этом вести диалог с пользователем о необходимости продолжать ввод. После заполнения массива структур упорядочить его по заданному полю. Например, упорядочить государства по численности населения или в алфавитном порядке.
Методические указания к выполнению заданий
Структурные переменные, или просто структуры, - это объединение одной или более переменных, возможно разных типов, в одну область памяти, имеющую для простоты одно имя. Отдельные составные части одной переменной называются полями.
Термин структура в языке С\C++ соответствует двум разным по смыслу понятиям:
1. обозначение места в памяти, где располагается информация; далее это место называется структурной переменной;
2. правила формирования структурной переменной, используемые компилятором для выделения ей места памяти и организации доступа к полям; далее такие правила называются шаблоном (pattern) структуры.
Как и любая переменная, структурная переменная должна быть описана. Описание состоит из 2 шагов:
1. задание шаблона структуры;
2. собственно описание структурной переменной.
Каждый шаблон имеет собственное имя для того, чтобы компилятор мог различать различные шаблоны. В том случае, если в функции исполняется единственный шаблон, он может иметь имя «нет_имени», что задается пропуском pattern_name при описании шаблона. Имена шаблонов должны быть уникальными в пределах их области определения.
Синтаксис задания шаблонов:
struct pattern_name {
type1 field_name1;
type2 field_name2;
...
typen field_namen;
};
где pattern_name - имя шаблона, удовлетворяющее правилам задания идентификаторов языка С\C++; type1, type2, typen - любые типы, например: int, char, float; field-name1, field-name2, field_namen - имена полей, удовлетворяющие правилам задания идентификаторов языка С\C++.
Например:
struct BOOK {
char name[20];
char title[44];
int year;
float price;
};
Имена полей в одном шаблоне должны быть уникальными. Однако в разных шаблонах можно использовать совпадающие имена полей. Кроме того, имена шаблонов проверяются на уникальность друг с другом, а не с метками или именами переменных.
Как и простая переменная, шаблон имеет область определения (видимости). Если шаблон описан внутри блока { } - это локальный шаблон, видимый только из пределов данного блока, в частности из пределов конкретной функции. Если описание шаблона помещено вне блоков, такой шаблон видим во всех функциях ниже точки описания шаблона до границы файла. Нельзя описать шаблон с реквизитами extern.
Когда задан шаблон, может быть описана структурная переменная. Описание структурной переменной состоит из задания типа и имени структурной переменной.
Например:
struct BOOK first_book;// здесь описывается структурная переменная по приведенному ранее шаблону BOOK.
Компилятор выделит под переменную число байтов памяти, достаточное для хранения всех ее полей. В данном случае это 70 байт. Число байтов, выделенное под структурную переменную, не всегда равно сумме длин отдельных полей из-за влияния дополнительного фактора внутреннего представления структурных переменных, называемого выравниванием. Точно выделенное число байтов всегда возвращает операция sizeof(struct pattern_name).
Например: sizeof (struct BOOK)
Синтаксис языка С\C++ разрешает совмещать описание шаблона и структурной переменной.
Например:
struct BOOK {
char name [20];
char title [44];
int year;
float price;
} first_book, child_book;
Для доступа к отдельным полям структурной переменной исполняют операцию ’.’ , формируя ссылку на нужное поле из имени структурной переменной и имени нужного поля. Такая ссылка может располагаться в любом месте выражений, где допустимы ссылки на простые переменные.
Например:
first_book.year = 1992;
strcopy ( child_book.title, "Белый Бим Черное ухо");
scanf ( "%f ", &first_book.price);
Ссылка на поле структурной переменной обладает всеми свойствами обычных переменных. Если поле - массив символов, как, например child_book.title, - это указатель-константа на первый элемент массива.
Можно определить адрес первого байта поля структурной переменной обычной операцией взятия адреса. Например: &first_book.price - адрес первого байта поля. Если структура переменных соответствует одному шаблону, допускаются операции присваивания таких структур переменных.
Например: first_book = child_book;
Эта операция приводит к физической пересылке в памяти числа байтов, равного размеру шаблона структурной переменной.
При описании структурной переменной разрешается выполнять инициализацию полей переменной.
Например:
struct BOOK first_book={"Митчелл М.","Унесенные ветром",1991,5.25},
child_book={"Троепольский Г.Н.","Белый Бим Черное Ухо",1980,2.78};
Разрешается объединять задание шаблона, описание структурных переменных и их инициализацию в одном предложении.
Для упрощения описания структурных переменных можно исполнять оператор typedef описания собственного типа данных. Это упрощает текст программы и экономит силы на повторный набор слова struct при описании структурных переменных. Общая форма конструирования собственного типа данных:
typedef описание_типа имя_нового_типа;
Например:
typedef struct BOOK {
char name [20];
char title [44];
int year;
float price;
} MY_BOOKS;
Затем можно использовать созданный тип для описания необходимых данных, например: MY_BOOKS dog_book, child_book;
Поле структурной переменной может иметь любой тип, в том числе и быть другой структурой. В этом случае его называют вложенной структурой. Шаблон вкладываемой структуры должен быть уже известен компилятору.
Например:
struct UDC {
char class_, subclass;
int number;
};
struct BOOK {
char name [20];
char title [44];
struct UDC udk_class;
int year;
float price;
} first_book, child_book;
Ссылка на поле вложенной структуры формируется из имени структурной переменной, имени структурного поля и имени поля вложенной структуры. Перечисленные имена разделяются символом ‘.’ (операция точка).
Например:
first_book.udc_class='A';
child_book.udc_class.number=681;
Структура не может вкладываться сама в себя. Разрешается использовать описываемый шаблон, если одно из полей является указателем на описываемую структуру.
Например:
struct BOOK {
struct BOOK *my_own;
char name[20];
char title[40];
int year;
float price;
};
Описание шаблона структуры вводит по существу новый тип. Раз так, то ничего не мешает использовать указатель на введенный тип. Для доступа к полям структурной переменной через указатель используется операция ®. Пример описания указателя на структурную переменную, инициализации указателя и его исполнения для ссылки на отдельные поля структурной переменной:
struct UDC {
char subclass;
int number;
};
struct BOOK {
struct UDC udc_class;
char name[20];
char title[44];
int year;
float price;
};
struct BOOK *ptr_book, first_book;
ptr_book=&first_book;
ptr_book->year = 1992;
ptr_book->udc_class.subclass='A';
ptr_book->udc_class.number=681;
scanf ("%d", &ptr_book->price);
Ссылка на поле структурной переменной через указатель обладает всеми свойствами обычной переменной, может располагаться как слева, так и справа от знака операции присваивания.
Для доступа к полям вложенной структуры используют сначала ®, а затем ссылку на поле вложенной структуры операции.
Например: ptr_book->udc_class.subclass='A';
Используя указатель на структурную переменную можно сделать ссылку на поле любого типа, в том числе, например, на указатель. Пример доступа к полям структуры с исполнением указателя на структуру UDC, являющегося полем структуры BOOK:
struct UDC {
char subclass;
int number;
} my_class;
struct BOOK {
struct UDC *udc_class;
char name [20];
char title[44];
int year;
float price;
};
struct BOOK *ptr_book, first_book;
ptr_book=&first_book;
ptr_book->udc_class=&my_class;
ptr_book->year=1992;
ptr_book->udc_class->subclass='A';
ptr_book->udc_class->number=681;
Указатели на структурные переменные широко используются для доступа к структурам, размещаемым в динамически выделяемой памяти, при создании сложных структур данных - списков, стеков, деревьев и др., для передачи в качестве фактических аргументов функциям.
По заданному шаблону структуры можно описывать массивы структурных переменных.
Например:
typedef struct {
char name[20];
char title[44];
int year;
float price;
} BOOKS;
BOOKS library[25];
Доступ к элементам массива может осуществляться с использованием индекса или через указатель-константу, которым является имя массива.
Например:
library[i].year = 28;
(*(library + i)).year = 28;
(library + i)-> year = 28;
Если описать рабочий указатель и инициализировать его адресом первого элемента массива:
BOOKS library[25], *ptr = library;
то для доступа к i-му элементу массива используем указатель ptr:
(ptr + i) ® year = 28;
Продвижение указателя ptr операцией ++ или -- соответственно увеличивает или уменьшает его на размер типа BOOKS, то есть устанавливает на следующий элемент массива структурных переменных вперед или назад.