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

Лекция 8

Структуры в языке Си: основные понятия. Массивы структур. Указатели на структуры. Вложение структур. Структуры и функции. Объединения. Перечисления. Определение и использование новых типов данных. Классы имен.

1. Структуры в языке си: основные понятия

При решении задач вычислительной математики, информационного обеспечения и системного программирования очень часто приходится сталкиваться с наборами данных, имеющими достаточно сложную логическую организацию. Таковыми, например, являются всевозможные каталоги, статистические таблицы, информационные белютени и наборы данных, создаваемые компилятором при обработке программ на языках высокого уровня. В то же время, оперативная память ЭВМ организована крайне примитивно в логическом отношении, представляя собой последовательность занумерованных ячеек длинной в один байт каждая. Такое несоответствие логической сложности возникающих в приложениях структур данных и возможностей их машинного представления неизбежно должно вызывать значительные трудности при разработке программного обеспечения, заставляя программистов всякий раз решать непростую задачу отображения этих структур данных на линейную структуру памяти ЭВМ. Возможный путь решения возникающей проблемы состоит в создании языков программирования, поддерживающих такую логическую организацию данных, которая наиболее типична для широкого круга прикладных задач. К подобным языкам, в частности, относится и язык Си, обладающий чрезвычайно мощными средствами представления и обработки сложных агрегатов данных. В Лекциях 3 и 4 мы уже рассмотрели одно- и многомерные массивы переменных, определив их как упорядоченные последовательности элементов данных одного типа. Не вызывает никаких сомнений, что понятие массива является одним из важнейших понятий всякой языковой системы, предназначенной для формализованного описания вычислительных алгоритмов. Однако статичность и однородность массивов в том виде, как они были определены ранее, несколько ограничивает возможность их применения для описания внутренних логических связей реальных информационных систем. В этой лекции рассматриваются более сложные агрегаты данных, называемые структурами, для которых требование однородности уже не имеет места. Сами же структуры могут быть объединены в массивы или вкладываться одна в другую, предоставляя тем самым возможность необычайно гибкой логической организации данных. Под структурой в языке Си понимается набор одной или большего числа переменных, возможно имеющих различный тип и объединенных под единым именем, называемым именем структуры. Последнее должно быть правильным идентификатором в смысле грамматики языка (см. Лекцию 1, $ 3). Описание всякой структуры в программе начинается с ключевого слова struct и в простейшем случае имеет следующий формат:

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

где struct есть ключевое слово языка Си, а в угловые скобки (<>) заключена необязательная часть конструкции. Здесь member-declaration list есть одно или более описаний переменных, каждая из которых называется элементом структуры, а identifier - суть имя переменной, определяемой как имеющей тип структура. Так, например, инструкция

struct { char name[30];

int group; } student;

определяет структуру с именем student, элементами которой являются массив символов name и целочисленная переменная group. Каждое из описаний в member-declaration list имеет тот же самый формат, что и рассмотренные ранее описания обычных переменных или массивов, однако здесь недопустимо использование описателей класса памяти (см. Лекцию 7, $ 2) и инициализирующих выражений (см. Лекцию 3, $ 3). Вся эта совокупность описаний, заключенная в фигурные скобки, определяет общую схему структуры и называется ее шаблоном. Всякий элемент структуры, входящий в состав шаблона, должен иметь свое собственное, уникальное в пределах данного шаблона, имя. Память под размещение отдельных элементов структуры выделяется компилятором последовательно, начиная с первого из них, чем гарантируется непрерывное хранение структуры в целом. Так в нашем примере, целочисленная переменная group, занимающая два байта, будет размещена сразу же после последнего элемента символьного массива name. Доступ к элементам структуры осуществляется путем указания ее идентификатора, за которым следует символ точка (.), и имени конкретного элемента этой структуры. Такая операция носит название операции получения элемента структуры, а ее приоритет так же высок, как и приоритет операции доступа к отдельным элементам массива (см. Лекцию 3, $ 1). Например, обозначение

student.group

задает элемент group в составе структуры student, в то время как ссылка

student.name[9]

выделяет десятый элемент массива name той же структуры. В отличие от имени массива, имя структуры само по себе не является синонимом своего имени. По существу это означает, что употребление имени структуры без следующего за ним символа операции получения элемента (.) и его имени не является допустимым и приводит к ошибке на этапе компиляции программы. Для получения же адреса начала структуры необходимо явным образом применить операцию & (см. Лекцию 4, $ 1) к имени структуры или ее первого элемента. Например, следующие два адресных выражения

&student и &student.name[0]

полностью эквивалентны и их значения равны адресу размещения структуры student в памяти ЭВМ. Совершенно аналогично, выражение

&student.group

определяет адрес элемента group в составе рассматриваемой структуры. Рассмотренный нами простейший способ определения структур требует всякий раз повторять шаблон структуры в каждом новом описании, даже если эти описания определяют структуры с одной и той же общей схемой. Чтобы избежать такого повторения, язык Си предоставляет возможность снабдить шаблон создаваемой структуры некоторым именем, называемым тегом структуры. Поэтому более общий способ описания структур в программе имеет следующий формат:

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

где tag является именем, присваеваемым шаблону структуры, а все остальные обозначения сохраняют свой прежний смысл. После своего определения в программе, тег структуры совместно с ключевым словом struct может быть использован как синтаксический эквивалент имени типа данных, т. е. допустимыми являются последующие описания вида

struct tag identifier <, identifier ... >;

определяющие имя identifier как имеющее тип struct tag. В следующем примере

struct DATE { int day;

int month;

int year;

char day_name[15];

char mon_name[15]; } date_1;

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

struct DATE date_2;

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

struct STACK { int pointer;

float vector[100]; };

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

struct STACK stack;

имеющую ранее фиксированный шаблон. Ссылки же на отдельные элементы структуры stack задаются в этом случае обычным образом

stack.vector[9]

что соответствует обращению к десятому элементу массива vector в составе структуры stack. В инструкциях описания структур, как и при определении обычных переменных или массивов, может содержаться дополнительная информация о классе памяти (см. Лекцию 7, $ 2) в виде соответствующего описателя, стоящего перед ключевым словом struct:

static struct STACK memory;

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

struct DATE date_3 = { 17, 3, 1989,

"пятница",

"февраль" };

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