LINUX.ORG.RU

Как правильно вернуть из функции динамический массив/матрицу

 


0

1

В общем решил немного изучить fortran (for fun), решил написать одну программку, которая делает некоторые расчеты.

Данные идут из файла, количество данных не фиксировано, поэтому массив (по идее) должен быть динамическим. Пишу real, dimension(:), allocatable :: m, а emacs’овский fortran-mode ругается на то, что ALLOCATABLE attribute conflicts with RESULT attribute, хотя gfortran даже не давится с -Wall -Wpedantic -Wextra. Код:

  function get_map() result(m)
    implicit none
    integer, dimension(:), allocatable :: m ! fortran-mode ругается именно тут
    allocate(m(15)) ! пока так, потом напишу функцию, которая возвращает кол-во элементов
    open(unit = 1, file = 'field2.txt', status = 'old')
    read (1, *) m
    close(1)
    print *, m
  end function get_map

В общем, мой вопрос: все ли так я делаю и не обращать внимание на то, что ругается fortran-mode?

Ну и спрошу сразу, чтоб отдельную тему не создавать - читать большую книгу по fortran как-то лень, поэтому посоветуйте какой-то интернет ресурс, где вкратце бы пояснялся fortran и то как делать надо, а как не надо.

★★★

По православному нужно так:

integer, allocatable :: m(:)

Но как у тебя тоже всё должно работать, просто более старый стандарт.

yvv ★★☆
()

У тебя кстати вся функция как-то неправильно оформлена. И вообще это не функция, а процедура, похоже.

yvv ★★☆
()
Ответ на: комментарий от yvv

Я немного поменял:

module two_d
  use utility
  implicit none
  type map
     real, dimension(:), allocatable :: xs, hs
  end type map


contains
  function get_map() result(m)
    implicit none
    type(map) ::  m
    integer :: N, i
    character(len=10) :: file_name

    file_name = 'field2.txt'

    N = get_num_rows(file_name)

    allocate(m%xs(N))
    allocate(m%hs(N))

    open(unit = 1, file = file_name, status = 'old')
    do i = 1, N
       read (1, *) m%xs(i), m%hs(i)
    end do

    close(1)
    return
  end function get_map

end module

Если убрать dimension, то он начинает ругаться. Он правда и сейчас ругается на вызов и я еще разбираюсь почему:

gfortran -Wall -Wpedantic -Wextra utility.f90 two_d.f90 main.f90 
main.f90:4:20:

    4 |   print *, get_map()
      |                    1
Error: Data transfer element at (1) cannot have ALLOCATABLE components unless it is processed by a defined input/output procedure

У тебя кстати вся функция как-то неправильно оформлена

Примеры смотрю тут http://www.mathcs.emory.edu/~cheung/Courses/561/Syllabus/6-Fortran/

И вообще это не функция, а процедура, похоже.

Возможно, я еще разбираюсь чем оно отличается. В Raku они отличаются тем, что function умеет возвращать значение, а subroutine - нет

snake266 ★★★
() автор топика
Последнее исправление: snake266 (всего исправлений: 1)
Ответ на: комментарий от snake266

Он правда и сейчас ругается на вызов

Все, понял, оно же возвращает составной тип и не знает как его распечатать:

  type(map) :: x

  x = get_map()
  print *, x%xs
  print *, x%hs
snake266 ★★★
() автор топика
Ответ на: комментарий от snake266

ну так надо intent(out) как бы в объявление переменной. Там где type(map), intent(out) :: m

Еще если функция, а не subroutine, то нифига напечатать не получится.

И книгу сейчас еще вспомню посоветую. Хотя изначально кажется достаточно простой и красивый синтаксис, тонкостей много. Лучше книга (есть таковая).

sshestov ★★
()
Ответ на: комментарий от sshestov

Книга такая: Илья Чернов «Фортран сегодня». Очень, очень рекомендую к прочтению, потому как тонкостей весьма много и они повсюду.

https://sites.google.com/site/fortrantoday/books/book

sshestov ★★
()
Последнее исправление: sshestov (всего исправлений: 1)
Ответ на: комментарий от sshestov

Спасибо за книгу, обязательно прочитаю! Она как раз небольшая.

snake266 ★★★
() автор топика
Ответ на: комментарий от sshestov

Да, тонкостей много, по примерам в интернете на stackoverflow не научишься)

snake266 ★★★
() автор топика
Ответ на: комментарий от snake266

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

type map
     real, dimension(:), allocatable :: xs, hs
end type map

.....

allocate(m%xs(N))
allocate(m%hs(N))

Делай так

type map
     real :: xs, hs
end type map

.....

type(map), allocatable :: m(:)

allocate(m(N))
yvv ★★☆
()
Последнее исправление: yvv (всего исправлений: 3)

Мнение эксперта по фортрану с 20-ти летним стажем, так ничего в нём и не понимающего:

module two_d
  use utility
  implicit none
  type map
     real :: xs, hs
  end type map


contains
  subroutine get_map(m)
    type(map), allocatable, intent(out) ::  m(:)
    integer :: N, i
    character(len=10) :: file_name

    file_name = 'field2.txt'

    N = get_num_rows(file_name)

    allocate(m(N))

    open(unit = 1, file = file_name, status = 'old')
    do i = 1, N
       read (1, *) m(i)%xs, m(i)%hs
    end do

  end subroutine get_map

end module

Попробуй, должно вроде работать.

yvv ★★☆
()
Последнее исправление: yvv (всего исправлений: 1)
Ответ на: комментарий от yvv

Но ведь если я буду делать allocate(m(N)) он не будет знать куда это N деть: компилятор не соврет

two_d.f90:20:13:

   20 |     allocate(m(N))
      |             1
Error: Allocate-object at (1) is neither a data pointer nor an allocatable variable

Ну либо я не знаю какой-то хак.

snake266 ★★★
() автор топика
Ответ на: комментарий от yvv

Да, у меня было в обьявлении типа real, allocatable :: xs(:), hs(:). Сделал как у вас и теперь все компилируется

snake266 ★★★
() автор топика
Ответ на: комментарий от snake266

Финкция в фортране – это синтакцический сахар. Та же процедура (subroutine) с ограничениями.

yvv ★★☆
()
Ответ на: комментарий от snake266

Главное, чтобы считалось правильно.

yvv ★★☆
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.