首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >将动态分配的字符串数组从C传递到Fortran

将动态分配的字符串数组从C传递到Fortran
EN

Stack Overflow用户
提问于 2022-06-24 12:38:35
回答 1查看 84关注 0票数 2

我试图将一个动态分配的字符串数组(char ***str)从C传递给Fortran,但在取消引用Fortran中的C指针时,我似乎缺少了一些东西,从而生成了作为输出的垃圾字符串(请参阅下面的MWE )。

边问题

调用deallocate(fptr)是否足以阻止下面的程序泄漏内存(我认为不会)?如果没有,是否可以将msgs (C语言)从Fortran中解放出来?

再生产

代码语言:javascript
复制
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void str_alloc(char*** msgs, size_t * n) {
  *n = 3;
  int str_len = 10;
  (*msgs) = malloc(*n * sizeof(char*));
  for (int i = 0; i < *n; i++) {
    (*msgs)[i] = malloc((str_len + 1) * sizeof(char));
    strcpy((*msgs)[i], "012346789");
  }
}
代码语言:javascript
复制
program main
    use iso_c_binding
    implicit none
    interface
        subroutine str_alloc(msgs, n) bind(C, name="str_alloc")
            use iso_c_binding
            type(c_ptr), intent(out) :: msgs
            integer(c_size_t), intent(out) :: n
        end subroutine
    end interface

    integer, parameter :: STRLEN = 10
    character(kind=c_char, len=STRLEN), allocatable :: names(:)

    call str_array_from_c(names)

    contains
    subroutine str_array_from_c(strs)
        character(len=STRLEN), allocatable, intent(out) :: strs(:)

        type(c_ptr) :: cptr
        integer(c_size_t) :: i, n, lenstr
        character(kind=c_char, len=1), pointer :: fptr(:,:)

        call str_alloc(cptr, n)
        call c_f_pointer(cptr, fptr, [int(STRLEN, kind=c_size_t), n])
        allocate(strs(n))
        print*, "Output C-str array from fortran"
        do i = 1_c_size_t, n
            lenstr = cstrlen(fptr(:, i))
            strs(i) = transfer(fptr(1:lenstr,i), strs(i))
            print*, fptr(1:STRLEN, i), "|", strs(i)
        end do
        deallocate(fptr)
    end subroutine str_array_from_c

    !> Calculates the length of a C string.
    function cstrlen(carray) result(res)
        character(kind=c_char, len=1), intent(in) :: carray(:)
        integer :: res
        integer :: i
        do i = 1, size(carray)
          if (carray(i) == c_null_char) then
            res = i - 1
            return
          end if
        end do
        res = i
    end function cstrlen

end program main

编译

代码语言:javascript
复制
gcc -c -g -Wall -o cfile.o cfile.c
gfortran -g -Wall -o main.o cfile.o main.f90

输出

代码语言:javascript
复制
 Output C-str array from fortran
 0�P�|0�
 p�|
 !|

其他信息

在现实中,interface.

  • The Cstr_len是可变的,因此字符串数组是锯齿状的。据我所知,没有定义自定义类型的唯一解决方案是使用足够大的characters.
  • I的len=,相对地,我确信我的错误是如何取消引用指针,因为检查cptr的十六进制转储显示字符串存在

相关员额

How to pass arrays of strings from both C and Fortran to Fortran?

Passing an array of C-strings to Fortran (iso_c_binding)

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-06-24 22:17:41

在C端,您有一个指针数组,它与二维Fortran数组不一样。Fortran没有“指针数组”的概念,所以您必须有一个带有指针组件的派生类型数组。

首先,从C代码返回的cptr必须转换为派生类型的数组,其中的每个元素都包含指向字符串的指针。然后迭代其中的每一个,将子组件C_PTR转换为Fortran指针,然后是您的字符数组。

第二,您不能DEALLOCATE一些Fortran没有分配的东西。您必须调用C来释放这些字符串。

下面是您的Fortran代码的修订版,可以工作。C代码没有改变。

代码语言:javascript
复制
program main
    use iso_c_binding
    implicit none
    interface
        subroutine str_alloc(msgs, n) bind(C, name="str_alloc")
            use iso_c_binding
            type(c_ptr), intent(out) :: msgs
            integer(c_size_t), intent(out) :: n
        end subroutine
    end interface

    integer, parameter :: STRLEN = 10
    character(kind=c_char, len=STRLEN), allocatable :: names(:)

    call str_array_from_c(names)

    contains
    subroutine str_array_from_c(strs)
        character(len=STRLEN), allocatable, intent(out) :: strs(:)

        type(c_ptr) :: cptr
        type,bind(C) :: c_array_t
            type(c_ptr) :: s
        end type c_array_t
        type(c_array_t), pointer :: c_array(:)
        integer(c_size_t) :: i, n, lenstr
        character(kind=c_char, len=1), pointer :: fptr(:)

        call str_alloc(cptr, n)
        call c_f_pointer(cptr,c_array, [n])
        allocate(strs(n))
        print*, "Output C-str array from fortran"
        do i = 1_c_size_t, n
            call c_f_pointer(c_array(i)%s, fptr, [int(STRLEN, kind=c_size_t)])
            lenstr = cstrlen(fptr)
            strs(i) = transfer(fptr(1:lenstr), strs(i))
            print*, fptr(1:STRLEN), "|", strs(i)
        end do
    end subroutine str_array_from_c

    !> Calculates the length of a C string.
    function cstrlen(carray) result(res)
        character(kind=c_char, len=1), intent(in) :: carray(:)
        integer :: res
        integer :: i
        do i = 1, size(carray)
          if (carray(i) == c_null_char) then
            res = i - 1
            return
          end if
        end do
        res = i
    end function cstrlen

end program main

当我构建和运行它时,我得到:

代码语言:javascript
复制
 Output C-str array from fortran
 012346789|012346789
 012346789|012346789
 012346789|012346789
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72744199

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档