ция "." (точка). Сначала указывается имя переменной-структуры, а затем – имя ком-
поненты. Например:
z.im = 3.2;
d.month = 7;
p.birthdate.year = 1980;
p.salary = 2000.00;
Важно отметить, что не все возможные комбинации значений компонент
Структуры могут иметь смысл применительно к конкретной задаче. Например, тип
"Date", определенный выше, включает значения {50, 5, 1973} и {100, 22, 1815}, хотя
Дней с такими датами не существует. Т.о., определение этого типа не отражает реаль-
Ного положения вещей, но все же оно достаточно близко к практическим целям. От-
Ветственность за то, чтобы при выполнении программы не возникали подобные бес-
Смысленные значения, возлагается на программиста.
102
В программе 2.1 демонстрируется, как в исходном тексте на Си++ располага-
Ются описание типа структуры, объявление переменных и обращение к компонентам
Структуры.
struct SimpleStructure {
char c;
int i;
float f;
double d;
};
Void main()
{
SimpleStructure s1, s2;
s1.c = 'a';
s1.i = 1;
s1.f = 3.14f; // Буква 'f' в конце вещественной константы
// означает, что это константа типа float,
// а не double
s1.d = 0.00093;
s2.c = 'b';
s2.i = 2;
s2.f = 6.28f;
s2.d = 0.15;
}
Программа 2.1.
В программе 2.1 в функции "main()" создаются две переменные типа
"SimpleStructure" с именами "s1" и "s2". У каждой из этих переменных есть соб-
ственный набор компонент с именами "c", "i", "f", и "d". Т.е. "s1" и "s2" являются
наборами независимых переменных. Для выбора компонент внутри "s1" или "s2"
применяется _______операция "." (точка). Подобная запись применялась в предыдущих лек-
циях для обращения к функциям-членам объектов "cin" и "сout". Обращения к ком-
понентам классов в объектно-ориентированном Си++ очень похожи на обращения к
Компонентам структур.
Переменные типа структуры можно присваивать, передавать, как параметры
функции, и возвращать из функции в качестве результата. Например:
Person current;
Person set_current_person(Person& p)
{
Person prev = current;
current = p;
return prev;
}
Остальные операции, такие, как сравнение ("==" и "!="), для структур по умол-
Чанию не определены, но программист может их определить при необходимости.
Имя типа структуры можно использовать еще до того, как этот тип будет опре-
Делен, вплоть до момента, когда потребуется, чтобы стал известен размер структуры.
Например, допустимы следующие прототипы функций:
103
Struct S; // S - имя некоторого типа
S f();
void g(S v1);
Но эти функции нельзя вызывать, если тип "S" не определен:
Void h()
{
S a; // ошибка: S не объявлено
F(); // ошибка: S не объявлено
G(a); // ошибка: S не объявлено
}
Доступ к компонентам структуры через указатель
Во всех предыдущих примерах компоненты структур использовались в выра-
Жениях подобно обычным переменным. Аналогично обычным переменным, можно
Создавать указатели на переменные-структуры. Для доступа к компонентам структу-
ры через указатель применяется операция "->". Например:
void print_person(Person* p)
{
cout << p->name << '\n';
cout << p->birthdate.day << '\n';
cout << p->birthdate.month << '\n';
cout << p->birthdate.year << '\n';
cout << p->salary << '\n\n';
}
Функцию "print_person()" можно переписать в эквивалентном виде с по-
мощью операции разыменования указателя "*" и операции доступа к компонентам
структуры ".". Обратите внимание на скобки в записи "(*p).", которые необходимы,
поскольку приоритет операции "." выше, чем у "*":
void print_person(Person* p)
{
cout << (*p).name << '\n';
cout << (*p).birthdate.day << '\n';
cout << (*p).birthdate.month << '\n';
cout << (*p).birthdate.year << '\n';
cout << (*p).salary << '\n\n';
}
Использование указателей на структуры показано в программе 3.1. В функции
"main()" этой программы указателю "sp" cначала присваивается адрес "s1", и затем
с помощью операции "->" компонентам "s1" присваиваются начальные значения. За-
тем указателю "sp" присваивается адрес "s2", и компоненты этой структуры также
Инициализируются. Возможность динамического перенаправления на различные объ-
Екты является одним из важнейших свойств указателей, которые, в частности, полез-
Ны для реализации динамических структур данных (например, связного списка или
Стека).
struct ExStruct {
104
char c;
int i;
float f;
double d;
};
Void main()
{
ExStruct s1, s2;
ExStruct* sp = &s1;
sp->c = 'a';
sp->i = 1;
sp->f = 3.14f;
sp->d = 0.00093;
sp = &s2;
sp->c = 'b';
sp->i = 2;
sp->f = 6.28f;
sp->d = 2.5;
}
Программа 3.1.
В 7-й лекции (для реализации связного списка) и в 8-й лекции уже рассматри-
Валось понятие рекурсивных структур данных. Для создания в структуре ссылки на
Структуру такого же типа необходимо пользоваться указателем. В программе 3.2 соз-
Даются две структуры, содержащие ссылки друг на друга.
struct SelfReferential {
int i;
SelfReferential* sr;
};
Void main()
{
SelfReferential sr1, sr2;
sr1.sr = &sr2;
sr2.sr = &sr1;
sr1.i = 47;
sr2.i = 1024;
}
Программа 3.2.
Описание без указателя является недопустимым, т.к. в нем при описании ком-
Поненты структуры тип структуры используется в тот момент, когда этот тип еще не
определен полностью:
struct SelfReferential {
int i;
SelfReferential sr; // Недопустимое описание компоненты
};
Массивы и структуры
У массива и структуры есть общее свойство: оба этих типа данных являются
Типами с произвольным доступом. Но структура более универсальна, поскольку не
105
Требуется, чтобы типы всех ее компонент были одинаковы. С другой стороны, в неко-
Торых случаях массив предоставляет бoльшие возможности, т.к. индексы его элемен-
Тов могут вычисляться, а имена компонент структуры – это фиксированные иденти-
Фикаторы, задаваемые в описании типа.
Массивы и структуры могут комбинироваться различными способами. Напри-
мер, i -я компонента массива "a", который является компонентой структуры "r", обо-
Значается как
r.a[i]
Напротив, компонента с именем "s", входящая в i -ю компоненту-структуру
массива структур "a" обозначается как
a[i].s
В качестве примера далее приведено описание переменной "screen", которая
является двумерным массивом структур типа "Cell". Этот массив предназначен для
хранения содержимого текстового экрана размером 80х25 знакомест:
struct Cell {