Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Подбельский Фомин_Программирование на языке СИ_...doc
Скачиваний:
234
Добавлен:
10.08.2019
Размер:
53.81 Mб
Скачать

Указатели на структуры как компоненты структур.

Указатели на структуры как компоненты структур. В соответствии с синтаксисом языка компонентами структур могут быть данные любых типов, за исключением структур того же типа, что и определяемый структурный тип. Например, элементом структуры, как уже говорилось, может быть структура, тип которой уже определен. Обычна конструкция:

Здесь ранее определенная структура типа struct mix является элементом структуры типа struct hole.

В то же время элементом структуры может быть указатель на структуру того же типа, что и определяемый структурный тип:

В структурном типе "химический элемент" есть компонент next - указатель на структуру того же типа. С его помощью можно формировать списки (цепочки) интересующих нас элементов. Например, можно связать все элементы одной группы периодической таблицы химических элементов либо представить в виде единого списка всю таблицу Д. И. Менделеева.

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

В данном примере для организации перекрестных ссылок в структурах типа struct part использованы в качестве элементов указатели на объекты типа struct ceil. В структуры типа struct cell входят указатели на структуры типа struct part.

6.3. Структуры и функции

Для "взаимоотношения" структур и функций имеются две основные возможности: структура может быть возвращаемым функцией значением и структура может использоваться в параметрах функции. Кроме того, в обоих случаях могут использоваться указатели на объекты структурных типов. Итак, рассмотрим все перечисленные варианты.

• Функция может возвращать структуру как результат:

• Функция может возвращать указатель на структуру:

• Параметром функции может быть структура:

• Параметром функции может быть указатель на объект структурного типа:

При вызове функции fff( ) выделяется память для формального параметра, т.е. для вспомогательного объекта типа struct person. В этот объект переносится значение фактического параметра, заменяющего формальный параметр - структуру str. Далее выполняются действия, предусмотренные операторами тела функции fff( ). Эти действия не могут изменять структуру, использованную в качестве фактического параметра.

В случае, когда параметром служит указатель на объект структурного типа, действиями внутри тела функции ffff() можно изменить ту структуру вызывающей функции, которая адресуется фактическим параметром pst.

Имитация абстрактных типов данных.

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

В качестве примера введем абстрактный тип данных для рациональных дробей. Выше в §6.1 введен и поименован с помощью typedef как fraction структурный тип для представления рациональных дробей.

Определим функции, реализующие операции над рациональными дробями:

input( ) - ввод дроби;

out( ) - вывод дроби на дисплей;

add( ) - сложение;

sub( ) - вычитание;

mult( ) - умножение;

divide( ) - деление.

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

Оформим определение структурного типа "рациональная дробь" и набор прототипов перечисленных выше функций для операций над дробями в виде следующего файла:

Обратите внимание, что применение typedef позволило упростить название структурного типа. Вместо конструкции struct rational_fraction в прототипах функций и далее в программе используется более короткое обозначение fraction.

Определения функций, реализующих перечисленные операции над рациональными дробями, объединим в один файл следующего вида:

Приведенный набор функций демонстрирует все возможные сочетания возвращаемых значений и параметров функций при работе со структурами. Обратите внимание, что функции add(), divide() возвращают структуру типа fraction, которую нужно "разместить" в соответствующей структуре вызывающей программы. Функция sub( ) предусматривает передачу результата через параметр-указатель fraction * pdr. Функция mult( ) формирует динамический объект типа fraction и возвращает его адрес. В основной программе после обращения к mult( ) корректно будет освободить динамическую память с помощью функции free( ).

Следующая программа демонстрирует работу с рациональными дробями с помощью введенных функций:

Результаты выполнения программы:

Обратите внимание на необходимость явного освобождения памяти после выполнения функции mult( ), внутри тела которой для результата (для структуры типа fraction) явно выделяется память, и указатель на этот участок памяти передается в вызывающую программу. После печати результата out(*p) библиотечная функция free(p) освобождает память.