- •Предисловие
- •1. Элементы языка
- •1.1. Свободная форма записи программы
- •1.2. Консоль-проект
- •1.2.1. Создание проекта в CVF
- •1.2.2. Создание проекта в FPS
- •1.2.3. Операции с проектом
- •1.2.4. Файлы с исходным текстом
- •1.3. Операторы
- •1.4. Объекты данных
- •1.5. Имена
- •1.6. Выражения и операции
- •1.7. Присваивание
- •1.8. Простой ввод/вывод
- •1.8.1. Некоторые правила ввода
- •1.8.2. Ввод из текстового файла
- •1.8.3. Вывод на принтер
- •1.9. Рекомендации по изучению Фортрана
- •1.10. Обработка программы
- •2. Элементы программирования
- •2.1. Алгоритм и программа
- •2.2. Базовые структуры алгоритмов
- •2.2.1. Блок операторов и конструкций
- •2.2.2. Ветвление
- •2.2.3. Цикл
- •2.2.3.1. Цикл "с параметром"
- •2.2.3.2. Циклы "пока" и "до"
- •2.2.4. Прерывание цикла. Объединение условий
- •2.3. Программирование "сверху вниз"
- •2.3.1. Использование функций
- •2.3.2. Использование подпрограмм
- •2.3.3. Использование модулей
- •2.4. Этапы проектирования программ
- •2.5. Правила записи исходного кода
- •3. Организация данных
- •3.1. Типы данных
- •3.2. Операторы объявления типов данных
- •3.2.1. Объявление данных целого типа
- •3.2.2. Объявление данных вещественного типа
- •3.2.3. Объявление данных комплексного типа
- •3.2.4. Объявление данных логического типа
- •3.3. Правила умолчания о типах данных
- •3.4. Изменение правил умолчания
- •3.5. Буквальные константы
- •3.5.1. Целые константы
- •3.5.2. Вещественные константы
- •3.5.3. Комплексные константы
- •3.5.4. Логические константы
- •3.5.5. Символьные константы
- •3.6. Задание именованных констант
- •3.7. Задание начальных значений переменных. Оператор DATA
- •3.8. Символьные данные
- •3.8.1. Объявление символьных данных
- •3.8.2. Применение звездочки для задания длины строки
- •3.8.3. Автоматические строки
- •3.8.4. Выделение подстроки
- •3.8.5. Символьные выражения. Операция конкатенации
- •3.8.6. Присваивание символьных данных
- •3.8.7. Символьные переменные как внутренние файлы
- •3.8.8. Встроенные функции обработки символьных данных
- •3.8.9. Выделение слов из строки текста
- •3.9. Производные типы данных
- •3.9.1. Объявление данных производного типа
- •3.9.2. Инициализация и присваивание записей
- •3.9.2.1. Конструктор производного типа
- •3.9.2.2. Присваивание значений компонентам записи
- •3.9.2.3. Задаваемые присваивания записей
- •3.9.3. Выражения производного типа
- •3.9.4. Запись как параметр процедуры
- •3.9.5. Запись как результат функции
- •3.9.6. Пример работы с данными производного типа
- •3.9.7. Структуры и записи
- •3.9.7.1. Объявление и присваивание значений
- •3.9.7.2. Создание объединений
- •3.9.8. Итоговые замечания
- •3.10. Целочисленные указатели
- •3.11. Ссылки и адресаты
- •3.11.1. Объявление ссылок и адресатов
- •3.11.2. Прикрепление ссылки к адресатам
- •3.11.3. Инициализация ссылки. Функция NULL
- •3.11.4. Явное открепление ссылки от адресата
- •3.11.5. Структуры со ссылками на себя
- •3.11.6. Ссылки как параметры процедур
- •3.11.7. Параметры с атрибутом TARGET
- •3.11.8. Ссылки как результат функции
- •4. Массивы
- •4.1. Объявление массива
- •4.2. Массивы нулевого размера
- •4.3. Одновременное объявление объектов разной формы
- •4.4. Элементы массива
- •4.5. Сечение массива
- •4.6. Присваивание массивов
- •4.7. Маскирование присваивания
- •4.7.1. Оператор и конструкция WHERE
- •4.7.2. Оператор и конструкция FORALL
- •4.8. Динамические массивы
- •4.8.1. Атрибуты POINTER и ALLOCATABLE
- •4.8.2. Операторы ALLOCATE и DEALLOCATE
- •4.8.3. Автоматические массивы
- •4.9. Массивы - формальные параметры процедур
- •4.9.1. Массивы заданной формы
- •4.9.2. Массивы, перенимающие форму
- •4.9.3. Массивы, перенимающие размер
- •4.10. Использование массивов
- •4.11. Массив как результат функции
- •4.12. Встроенные функции для массивов
- •4.12.1. Вычисления в массиве
- •4.12.2. Умножение векторов и матриц
- •4.12.3. Справочные функции для массивов
- •4.12.3.1. Статус размещаемого массива
- •4.12.3.2. Граница, форма и размер массива
- •4.12.4. Функции преобразования массивов
- •4.12.4.1. Элементная функция MERGE слияния массивов
- •4.12.4.2. Упаковка и распаковка массивов
- •4.12.4.3. Переформирование массива
- •4.12.4.4. Построение массива из копий исходного массива
- •4.12.4.5. Функции сдвига массива
- •4.12.4.6. Транспонирование матрицы
- •4.13. Ввод/вывод массива под управлением списка
- •4.13.1. Ввод/вывод одномерного массива
- •4.13.2. Ввод/вывод двумерного массива
- •5. Выражения, операции и присваивание
- •5.1. Арифметические выражения
- •5.1.1. Выполнение арифметических операций
- •5.1.2. Целочисленное деление
- •5.1.3. Ранг и типы арифметических операндов
- •5.1.4. Ошибки округления
- •5.2. Выражения отношения и логические выражения
- •5.3. Задаваемые операции
- •5.4. Приоритет выполнения операций
- •5.5. Константные выражения
- •5.6. Описательные выражения
- •5.7. Присваивание
- •6. Встроенные процедуры
- •6.1. Виды встроенных процедур
- •6.2. Обращение с ключевыми словами
- •6.3. Родовые и специфические имена
- •6.4. Возвращаемое функцией значение
- •6.5. Элементные функции преобразования типов данных
- •6.6. Элементные числовые функции
- •6.7. Вычисление максимума и минимума
- •6.8. Математические элементные функции
- •6.8.1. Экспоненциальная, логарифмическая функции и квадратный корень
- •6.8.2. Тригонометрические функции
- •6.9. Функции для массивов
- •6.10. Справочные функции для любых типов
- •6.11. Числовые справочные и преобразовывающие функции
- •6.11.1. Модели данных целого и вещественного типа
- •6.11.2. Числовые справочные функции
- •6.12. Элементные функции получения данных о компонентах представления вещественных чисел
- •6.13. Преобразования для параметра разновидности
- •6.14. Процедуры для работы с битами
- •6.14.1. Справочная функция BIT_SIZE
- •6.14.2. Элементные функции для работы с битами
- •6.14.3. Элементная подпрограмма MVBITS
- •6.14.4. Пример использования битовых функций
- •6.15. Символьные функции
- •6.16. Процедуры для работы с памятью
- •6.17. Проверка состояния "конец файла"
- •6.18. Неэлементные подпрограммы даты и времени
- •6.19. Случайные числа
- •6.20. Встроенная подпрограмма CPU_TIME
- •7. Управляющие операторы и конструкции
- •7.1. Оператор GOTO безусловного перехода
- •7.2. Оператор и конструкции IF
- •7.2.1. Условный логический оператор IF
- •7.2.2. Конструкция IF THEN END IF
- •7.2.3. Конструкция IF THEN ELSE END IF
- •7.2.4. Конструкция IF THEN ELSE IF
- •7.3. Конструкция SELECT CASE
- •7.4. DO-циклы. Операторы EXIT и CYCLE
- •7.5. Возможные замены циклов
- •7.6. Оператор STOP
- •7.7. Оператор PAUSE
- •8. Программные единицы
- •8.1. Общие понятия
- •8.2. Использование программных единиц в проекте
- •8.3. Работа с проектом в среде DS
- •8.4. Главная программа
- •8.5. Внешние процедуры
- •8.6. Внутренние процедуры
- •8.7. Модули
- •8.8. Оператор USE
- •8.9. Атрибуты PUBLIC и PRIVATE
- •8.10. Операторы заголовка процедур
- •8.10.1. Общие характеристики операторов заголовка процедур
- •8.10.2. Результирующая переменная функции
- •8.11. Параметры процедур
- •8.11.1. Соответствие фактических и формальных параметров
- •8.11.2. Вид связи параметра
- •8.11.3. Явные и неявные интерфейсы
- •8.11.4. Ключевые и необязательные параметры
- •8.11.5. Ограничения на фактические параметры
- •8.11.6. Запрещенные побочные эффекты
- •8.12. Перегрузка и родовые интерфейсы
- •8.12.1. Перегрузка процедур
- •8.12.2. Перегрузка операций и присваивания
- •8.12.3. Общий вид оператора INTERFACE
- •8.13. Ассоциирование имен
- •8.14. Область видимости имен
- •8.15. Область видимости меток
- •8.16. Ассоциирование памяти
- •8.16.1. Типы ассоциируемой памяти
- •8.16.2. Оператор COMMON
- •8.16.3. Программная единица BLOCK DATA
- •8.17. Рекурсивные процедуры
- •8.18. Формальные процедуры
- •8.18.1. Атрибут EXTERNAL
- •8.18.2. Атрибут INTRINSIC
- •8.19. Оператор RETURN выхода из процедуры
- •8.20. Оператор ENTRY дополнительного входа в процедуру
- •8.21. Атрибут AUTOMATIC
- •8.22. Атрибут SAVE
- •8.23. Атрибут STATIC
- •8.24. Атрибут VOLATILE
- •8.25. Чистые процедуры
- •8.26. Элементные процедуры
- •8.27. Операторные функции
- •8.28. Строка INCLUDE
- •8.29. Порядок операторов и директив
- •9. Форматный ввод/вывод
- •9.1. Преобразование данных. Оператор FORMAT
- •9.2. Программирование спецификации формата
- •9.3. Выражения в дескрипторах преобразований
- •9.4. Задание формата в операторах ввода/вывода
- •9.5. Списки ввода/вывода
- •9.5.1. Элементы списков ввода/вывода
- •9.5.2. Циклические списки ввода/вывода
- •9.5.3. Пример организации вывода
- •9.6. Согласование списка ввода/вывода и спецификации формата. Коэффициент повторения. Реверсия формата
- •9.7. Дескрипторы данных
- •9.8. Дескрипторы управления
- •9.9. Управляемый списком ввод/вывод
- •9.9.1. Управляемый именованным списком ввод/вывод
- •9.9.1.1. Объявление именованного списка
- •9.9.1.2. NAMELIST-вывод
- •9.9.1.3. NAMELIST-ввод
- •9.9.2. Управляемый неименованным списком ввод/вывод
- •9.9.2.1. Управляемый неименованным списком ввод
- •9.9.2.2. Управляемый неименованным списком вывод
- •10. Файлы Фортрана
- •10.1. Внешние и внутренние файлы
- •10.2. Позиция файла
- •10.3. Устройство ввода/вывода
- •10.4. Внутренние файлы
- •10.5. Внешние файлы
- •10.6. Записи
- •10.6.1. Типы записей
- •10.6.2. Записи фиксированной длины
- •10.6.3. Записи переменной длины
- •10.6.4. Сегментированные записи
- •10.6.5. Потоки
- •10.6.6. CR-потоки
- •10.6.7. LF-потоки
- •10.7. Передача данных с продвижением и без
- •10.8. Позиция файла перед передачей данных
- •10.9. Позиция файла после передачи данных
- •10.10. Двоичные последовательные файлы
- •10.11. Неформатные последовательные файлы
- •10.12. Текстовые последовательные файлы
- •10.13. Файлы, подсоединенные для прямого доступа
- •10.14. Удаление записей из файла с прямым доступом
- •10.15. Выбор типа файла
- •11. Операции над внешними файлами
- •11.1. Оператор BACKSPACE
- •11.2. Оператор REWIND
- •11.3. Оператор ENDFILE
- •11.4. Оператор OPEN
- •11.5. Оператор CLOSE
- •11.6. Оператор READ
- •11.7. Оператор ACCEPT
- •11.8. Оператор FIND
- •11.9. Оператор DELETE
- •11.10. Оператор UNLOCK
- •11.11. Оператор WRITE
- •11.12. Оператор PRINT
- •11.13. Оператор REWRITE
- •11.14. Оператор INQUIRE
- •11.15. Функция EOF
- •11.16. Организация быстрого ввода/вывода
- •12.1. Некоторые сведения об объектах ActiveX
- •12.2. Для чего нужен конструктор модулей
- •12.3. Интерфейсы процедур управления Автоматизацией
- •12.4. Идентификация объекта
- •12.5. Примеры работы с данными Автоматизации
- •12.5.1. OLE-массивы
- •12.5.2. BSTR-строки
- •12.5.3. Варианты
- •12.6. Другие источники информации
- •12.7. Как воспользоваться объектом ActiveX
- •12.8. Применение конструктора модулей
- •12.9. Пример вызова процедур, сгенерированных конструктором модулей
- •Приложение 1. Вывод русского текста в DOS-окно
- •Приложение 2. Нерекомендуемые, устаревшие и исключенные свойства Фортрана
- •П.-2.1. Нерекомендуемые свойства Фортрана
- •П.-2.1.1. Фиксированная форма записи исходного кода
- •П.-2.1.2. Оператор EQUIVALENCE
- •П.-2.1.3. Оператор ENTRY
- •П.-2.1.4. Вычисляемый GOTO
- •П.-2.1.5. Положение оператора DATA
- •П.-2.2. Устаревшие свойства Фортрана, определенные стандартом 1990 г.
- •П.-2.2.1. Арифметический IF
- •П.-2.2.2. Оператор ASSIGN присваивания меток
- •П.-2.2.3. Назначаемый GOTO
- •П.-2.2.4. Варианты DO-цикла
- •П.-2.2.5. Переход на END IF
- •П.-2.2.6. Альтернативный возврат
- •П.-2.2.7. Дескриптор формата H
- •П.-2.3. Устаревшие свойства Фортрана, определенные стандартом 1995 г.
- •П.-2.4. Исключенные свойства Фортрана
- •Приложение 3. Дополнительные процедуры
- •П.-3.1. Запуск программ
- •П.-3.2. Управление программой
- •П.-3.3. Работа с системой, дисками и директориями
- •П.-3.4. Управление файлами
- •П.-3.5. Генерация случайных чисел
- •П.-3.6. Управление датой и временем
- •П.-3.7. Ввод с клавиатуры и генерация звука
- •П.-3.8. Обработка ошибок
- •П.-3.9. Аргументы в командной строке
- •П.-3.10. Сортировка и поиск в массиве
- •П.-3.11. Управление операциями с плавающей точкой
- •Литература
- •Предметный указатель
- •Оглавление
риложение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