Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции_СП_2004_1_00.doc
Скачиваний:
69
Добавлен:
04.11.2018
Размер:
882.69 Кб
Скачать

2. Массивы структур

Отдельные структуры с произвольным общим шаблоном, как и обычные переменные любого типа, могут быть объединены в массивы фиксированной длины. С точки зрения общей теории баз данных такая операция соответствует заданию ограниченного вектора, элементами которого являются объекты некоторого абстрактного структурированного типа. Описания массивов структур в программе строятся на той же самой синтаксической основе, что и описания обычных массивов. Так, в следующем примере

struct BOOK { char author[30]; /* Автор книги */

char title[256]; /* Название книги */

int year; /* Год издания */

int pages; /* Количество страниц */

} catalog[10]; /* Массив структур */

имя catalog об'явлено как массив десяти структур с общим шаблоном BOOK. Организация данных, подобная этой, может быть использована, например, при составлении библиографических каталогов. Для обращения к отдельным элементам массива структур его имя всякий раз необходимо модифицировать при помощи квадратных скобок ([]), задающих операцию взятия элемента массива. Конкретный элемент выбранной из массива структуры выделяется в этом случае обычным образом при помощи символа точка (.). Так, обращение вида

catalog[3].title[4]

задает пятый символ массива title элементов типа char в составе четвертого элемента массива структур catalog. Применяя к какому-либо элементу массива операцию & получения адреса

&catalog[7]

можно найти начало размещения в памяти соответствующей структуры. Замечание. Поскольку имя всякого массива является синонимом своего адреса, то упоминание самого по себе имени массива структур тождественно операции получения адреса нулевого элемента этого массива. В частности, для массива структур catalog из предыдущего примера справедливы равенства

catalog == &catalog[0].author[0] == catalog[0].author

3. Указатели на структуры

В предыдущем параграфе, определяя понятие массива структур, мы сделали первый шаг к пониманию того, что тип struct является совершенно полноправным типом данных языка Си. Теперь, расширяя наши представления о структурах, попробуем определить понятие указателя на структуру и придать ему конкретный смысл в программе. Формально указатель на структуру можно описать подобно тому, как мы это делали для указателей на простые типы данных. Общая схема такого описания должна иметь, видимо, один из следующих форматов:

struct <tag> { member-declaration list } *identifier <, ... >;

или

struct tag *identifier <, ... >;

что находится в полном соответствии с синтаксическими правилами составления описаний в языке Си. В частности, возвращаясь в примерам предыдущих параграфов, мы могли бы написать

struct STUDENT { char name[30];

int group; } *studptr;

определяя тем самым указатель studptr на структурный тип STUDENT. При этом комбинация *studptr должна рассматриваться как сама структура и формально можно задать ссылку на ее отдельный элемент, используя операцию точка (.):

(*studptr).group

Заметим, что в этом примере, как и при определении указателей на массивы (см. Лекцию 4, $ 3), круглые скобки являются существенными, поскольку стандартный приоритет операции получения элемента (.) выше приоритета операции косвенной адресации (*). Однако последняя запись может и не иметь конкретного смысла, поскольку создавая указатель на структуру компилятор не выделяет реальную память под хранение ее элементов. Эта ситуация полностью аналогична той, с которой мы столкнулись в Лекции 4, рассматривая эквивалентность массивов и указателей. В то же время, указатели на структуры обеспечивают принципиальную возможность более гибкого манипулирования данными, нежели сами структуры, поскольку используя аппарат указателей память под размещение элементов структуры можно выделять динамически при помощи функций alloca(), malloc() или realloc() (см. Лекцию 4, $ 4). Так, например, воспользовавшись первой из этих функций, мы можем написать

studptr = (struct STUDENT*)alloca(n*sizeof(struct STUDENT));

зарезервировав тем самым блок памяти, достаточный для размещения массива n структур с шаблоном STUDENT. Теперь, используя обозначения последнего примера, попробуем придать конкретный смысл арифметическим операциям над указателями на структуры. Вспоминая, что увеличивая на единицу значение указателя на простой тип данных, мы заставляли его ссылаться на очередной элемент данных соответствующего типа, нетрудно понять, что операции вида

studptr = studptr + 1 или studptr++

смещают указатель на структурный тип STUDENT на начало очередной структуры этого типа. Используя далее общее понятие эквивалентности массивов и указателей, можно проиндексировать указатель на структуру, понимая эту операцию в смысле равенства адресов

studptr + i == &studptr[i]

или в контексте выделения отдельного элемента структуры

(*(studptr+i)).name[k] == studptr[i].name[k]

Для удобства выделения элементов структур, заданных своими указателями, в языке Си дополнительно введена операция следования, знаком которой является комбинация -> символов '-' и '>'. Ее приоритет совпадает с приоритетом обычной операции получения элемента структуры. Используя эту операцию в нашем примере, вместо обозначения

(*studptr).name

определяющего адрес массива name в составе структуры с указателем studptr, следует писать

studptr->name

что семантически совершенно эквивалентно предыдущей записи.