我试图将一个动态分配的字符串数组(char ***str)从C传递给Fortran,但在取消引用Fortran中的C指针时,我似乎缺少了一些东西,从而生成了作为输出的垃圾字符串(请参阅下面的MWE )。
边问题
调用deallocate(fptr)是否足以阻止下面的程序泄漏内存(我认为不会)?如果没有,是否可以将msgs (C语言)从Fortran中解放出来?
再生产
#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");
}
}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编译
gcc -c -g -Wall -o cfile.o cfile.c
gfortran -g -Wall -o main.o cfile.o main.f90输出
Output C-str array from fortran
0�P�|0�
p�|
!|其他信息
在现实中,interface.
str_len是可变的,因此字符串数组是锯齿状的。据我所知,没有定义自定义类型的唯一解决方案是使用足够大的characters.len=,相对地,我确信我的错误是如何取消引用指针,因为检查cptr的十六进制转储显示字符串存在。

相关员额
How to pass arrays of strings from both C and Fortran to Fortran?
发布于 2022-06-24 22:17:41
在C端,您有一个指针数组,它与二维Fortran数组不一样。Fortran没有“指针数组”的概念,所以您必须有一个带有指针组件的派生类型数组。
首先,从C代码返回的cptr必须转换为派生类型的数组,其中的每个元素都包含指向字符串的指针。然后迭代其中的每一个,将子组件C_PTR转换为Fortran指针,然后是您的字符数组。
第二,您不能DEALLOCATE一些Fortran没有分配的东西。您必须调用C来释放这些字符串。
下面是您的Fortran代码的修订版,可以工作。C代码没有改变。
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当我构建和运行它时,我得到:
Output C-str array from fortran
012346789|012346789
012346789|012346789
012346789|012346789https://stackoverflow.com/questions/72744199
复制相似问题