C向Fortran传递动态字符串数组的解引用错误与内存问题
核心错误原因
你当前的指针解引用逻辑存在本质错误:
C侧返回的char***是三级指针,其指向的第一层内存是长度为n的char*类型指针数组,每个数组元素存储的是单个C字符串的首地址,并非连续排布的二维字符内存块。你直接将外层cptr绑定为形状[STRLEN, n]的二维Fortran字符数组,本质是把存储指针地址值的内存段直接当做字符内容读取,最终必然输出乱码。
修正方案
正确的解引用需要分两层做指针转换:
- 首先将外层
cptr绑定为type(c_ptr)类型的一维数组,对应C侧的char* str_ptr_array[n] - 遍历上述指针数组的每个元素,将单个字符串的
c_ptr单独绑定为一维单字符Fortran指针,再做长度计算、内容拷贝,天然适配你提到的不规则锯齿字符串数组场景。
修正后的Fortran代码
program main use iso_c_binding implicit none ! 声明C标准库free函数接口,用于释放C侧内存 interface subroutine c_free(ptr) bind(C, name="free") import :: c_ptr type(c_ptr), value :: ptr end subroutine end interface 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 ! 设为足够容纳最长C字符串的长度即可,适配锯齿数组 integer, parameter :: MAX_STRLEN = 4096 character(kind=c_char, len=:), allocatable :: names(:) call str_array_from_c(names) print *, "Fortran侧拿到的字符串:" do i = 1, size(names) print *, trim(names(i)) end do contains subroutine str_array_from_c(strs) character(len=:), allocatable, intent(out) :: strs(:) type(c_ptr) :: cptr type(c_ptr), pointer :: c_str_ptrs(:) ! 对应C侧的char*数组 integer(c_size_t) :: i, n, slen character(kind=c_char, len=1), pointer :: tmp_cstr(:) call str_alloc(cptr, n) ! 第一层绑定:拿到char*指针数组 call c_f_pointer(cptr, c_str_ptrs, [n]) allocate(character(len=MAX_STRLEN) :: strs(n)) do i = 1_c_size_t, n ! 第二层绑定:拿到单个C字符串的字符数组 call c_f_pointer(c_str_ptrs(i), tmp_cstr, [MAX_STRLEN]) slen = cstrlen(tmp_cstr) strs(i) = transfer(tmp_cstr(1:slen), strs(i)) ! 释放单个字符串的C内存 call c_free(c_str_ptrs(i)) end do ! 释放最外层char*数组的C内存 call c_free(cptr) nullify(c_str_ptrs, tmp_cstr) end subroutine str_array_from_c ! 计算C字符串(null终止)的实际长度 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
C侧代码无需修改,原有编译命令保持不变即可正常运行。
内存泄漏相关问题解答
- 原代码中
deallocate(fptr)的写法完全错误,不仅不能避免内存泄漏,还会触发未定义行为:fptr是通过c_f_pointer绑定的C侧内存,并非Fortran运行时自身分配的内存,绝对不能用Fortran的deallocate释放,轻则程序崩溃,重则内存随机破坏。 - Fortran侧可以安全释放C侧申请的内存,但必须调用C标准库的
free函数,严格按照C侧的分配层级释放:先遍历释放每个单独字符串的内存,再释放最外层存储char*指针的数组内存,即可完全避免内存泄漏。
内容的提问来源于stack exchange,提问作者gnikit
相关产品推荐
相关产品推荐

