Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
современный фортран , Бортеньев.pdf
Скачиваний:
242
Добавлен:
26.03.2015
Размер:
2.34 Mб
Скачать

риложение3. Организация данных

3.11.3. Инициализация ссылки. Функция NULL

Ссылку можно инициализировать, применив функцию NULL: real(4), dimension(:), pointer :: pa => null( )

Функция NULL дает ссылке статус "не ассоциирована с адресатом". Этот статус позволяет, например, использовать ссылку в качестве фактического параметра до ее прикрепления к адресату, например:

program null_test

real(4), dimension(:), pointer :: pa => null( ) interface

subroutine poas(pa)

real(4), dimension(:), pointer :: pa

end subroutine poas

 

end interface

 

call poas(pa)

! Параметр - неприкрепленная ссылка

print *, pa(2)

! 3.500000

end program null_test

 

subroutine poas(pa)

real(4), dimension(:), pointer :: pa allocate(pa(5))

pa = 3.5

end subroutine poas

Функция NULL может быть использована и среди исполняемых операторов:

pa => null( )

3.11.4. Явное открепление ссылки от адресата

Ссылку можно открепить от адресата, используя оператор NULLIFY:

NULLIFY(pname)

pname - список ссылочных переменных или компонентов структуры, которые следует открепить от их адресатов. Все элементы списка должны иметь атрибут POINTER. Например:

integer, pointer :: a(:), b, c(:, :, :)

...

nullify(a, b, c)

Кроме открепления от адресата, оператор NULLIFY можно использовать для инициализации (обнуления) ссылки. Не является ошибкой открепление неприкрепленной ссылки.

Оператор NULLIFY не освобождает адресата. Иными словами, если адресатом ссылки является выделенная оператором ALLOCATE память, то после открепления ссылки память не освобождается и остается недоступной, если к памяти была прикреплена лишь одна ссылка.

99

О. В. Бартеньев. Современный ФОРТРАН

Недоступная память не образуется, если предварительно память освобождается оператором DEALLOCATE. Например:

integer, pointer :: c(:, :, :)

...

allocate(c(2, 5, 10))

...

deallocate(c)

nullify(c)

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

integer, pointer :: a(:)

 

integer, target :: b(5)

 

...

! Адресатом ссылки a является выделяемая память

allocate(a(5))

...

! Выделенная ранее под ссылку a память становится

a => b

...

! недоступной для последующего использования

В следующем фрагменте переназначение ссылки выполнено без потери памяти:

allocate(a(5))

 

...

 

deallocate(a)

! Освобождение памяти. Память доступна для

a => b

! последующего использования

...

 

Заметим, что после выполнения оператора DEALLOCATE состояние ссылки становится неопределенным и может быть определено либо в результате присоединения к другому адресату, либо в результате обнуления в операторе NULLIFY.

3.11.5. Структуры со ссылками на себя

Компонент производного типа может иметь атрибут POINTER и при этом ссылаться на переменную того же или другого производного типа:

type entry

! Объявление типа entry

real val

 

integer index

! Ссылка на объект типа entry

type(entry), pointer :: next

end type entry

 

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

100

риложение3. Организация данных

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

Рис. 3.2. Схема однонаправленного списка с записями одинаковой длины

Разработаем программу формирования и редактирования однонаправленного списка. Пусть помимо поля с указателем каждый элемент списка содержит еще два поля, одно из которых (index) используется для индексирования элементов списка. Редактирование состоит из двух операций: добавления и удаления элемента из однонаправленного списка. Схема добавления элемента в однонаправленный список приведена на рис. 3.3, а удаления - на рис. 3.4.

Новый элемент

. . .

Рис. 3.3. Схема включения элемента в однонаправленный список

. . .

Удаляемый элемент

Рис. 3.4. Схема удаления элемента из однонаправленного списка

По приведенным рисункам легко записать алгоритмы формирования списка и его модификации.

101

О. В. Бартеньев. Современный ФОРТРАН

Алгоритм формирования списка из n элементов (оформлен в виде внутренней подпрограммы newtree):

1°. Начало (список формируется начиная с последнего элемента). 2°. Обнулить адрес последнего элемента списка tree - NULLIFY(tree). 3°. С параметром k = 1, n выполнить:

Выделить память под элемент top.

В поле с адресом элемента top занести адрес элемента, добавленного на шаге k - 1, т. е. адрес вершины tree. (Таким образом, каждый вновь добавляемый элемент (кроме

последнего элемента списка) будет указывать на предыдущий.) Переместить вершину списка на последний добавленный элемент, выполнив tree => top.

конец цикла 3°. 4°. Конец.

Приведем далее текст программы, которая позволяет формировать список из заданного числа элементов, выполнять его просмотр и редактирование.

module eni

! Модуль описания типа entry

type entry

 

real val

 

integer index

 

type(entry), pointer :: next

! Ссылка, которую можно присоединить

end type entry

! к переменной типа entry

end module eni

 

program one_d_li

! Формирование, просмотр

use eni

! и редактирование списка

type(entry), pointer :: tree, top, current, newtop

call newtree( )

! Список сформирован; top ссылается

 

! на последний элемент списка

call wali(top)

! Просмотр списка

tree => top

! Перемещение в вершину списка

call chava(5)

! Изменим поле val у двух соседних

call wali(top)

! Просмотр списка

call delem(7)

! Исключим из списка элемент с index = 7

call wali(top)

! Просмотр списка

tree => top

 

call insel(700.0, 8)

! Вставим элемент после элемента с index = 8

call wali(top)

! Просмотр списка

contains

 

subroutine newtree( )

! Создание списка

integer i

 

nullify(tree)

! Обнуляем конец списка. В конце списка

 

! ASSOCIATED(tree) будет возвращать .FALSE.

do i = 1, 10

! Цикл формирования списка

!Размещаем новый элемент списка и заносим информацию

!в поля с данными

102

 

риложение3. Организация данных

allocate(top)

! Ссылка top содержит в качестве

top = entry(11.0*i, i, tree)

! компонента ссылку tree

tree => top

! Установим указатель списка на

end do

! вновь добавленный элемент

end subroutine newtree

 

subroutine wali(top)

! Просмотр списка начиная с элемента top

type(entry), pointer :: top

! Прикрепляем ссылку tree к top

tree => top

do while(associated(tree))

! Цикл просмотра списка

print *, tree%val, tree%index

 

current => tree%next

! Переход к следующему элементу

tree => current

 

end do

 

read *

! Ожидаем нажатия Enter

end subroutine wali

 

subroutine delem(ind)

! Удаление элемента из списка

integer ind

 

tree => top

 

do while(associated(tree))

! Следующий элемент имеет index = 7

if(tree%index == ind) then

!Присоединим указатель элемента с index = in к указателю элемента

!с index = in + 2, выполнив тем самым исключение элемента с index = in + 1 if(associated(tree%next)) then

current => tree%next

tree%next => tree%next%next

deallocate(current)

! Освобождаем память после исключения

end if

! элемента из списка

exit

 

end if

 

current => tree%next

 

tree => current

 

end do

 

end subroutine delem

 

subroutine insel(val, ind)

! Добавляет элемент в список tree

integer ind

 

real val

 

do while(associated(tree))

 

if(tree%index == ind) then

 

allocate(newtop)

 

newtop = entry(val, ind - 1, tree%next)

tree%next => newtop

 

if(tree%index > 1) then

 

newtop%next => tree%next%next

else

! При вставке вслед за последним

nullify(newtop%next)

! элементом обнуляем ссылку

end if

 

103