【问题标题】:Freeing a C pointer returned by a C function to Fortran?将 C 函数返回的 C 指针释放到 Fortran?
【发布时间】:2016-08-17 13:36:46
【问题描述】:

我有一个函数,它在 C 中返回一个 char * 指针,看起来像这样

char * string_val (ARGS)
{
 char * svalue = cJSON_GetObjectItem(nml,var_name)->valuestring;
 return svalue;
}

在 Fortran 中,我将其分配给 C 指针(使用 iso_c_binding)

type (c_ptr) :: C_String_ptr
...
C_String_ptr = string_val (ARGS)

这部分效果很好。 string_val 函数被调用了很多,我认为它会导致内存泄漏。我正在尝试释放 svalue 指针的内存,但我刚刚遇到了 seg 错误和内存转储。我目前有这样的事情:

     subroutine c_mem_free (cptr) bind(C,name="c_mem_free")
      use iso_c_binding
      type (c_ptr)   :: cptr   !< The C pointer whose memory needs to be freed
     end subroutine
...
 call c_mem_free(C_String_ptr)

在哪里

 void c_mem_free (void** addrOfptr)
{
  free(*addrOfptr);    /* free the memory pointed to */
  *addrOfptr=NULL;     /* Nullify the pointer ;) */
}

回溯指向空闲线路上的问题。我也尝试将更改 cptr 传递给 value 所以 type (c_ptr),VALUE :: cptr 并且在 C 端有void*addrOfptrfree(addrOfptr),但这似乎也不起作用。我也没有成功在 Fortran 端找到 svalue 的内存位置。如果我使用类似的东西

write (6,'(z)')loc(C_String_ptr) write (6,'(z)')loc(c_loc(C_String_ptr))

这些都没有给我与 printf svalue 内存位置相同的值。 在 Fortran 中返回指针 svalue 后,如何释放它的内存?如何在 Fortran 中获取 svalue 内存的位置?

【问题讨论】:

  • 如果程序完全用C编写,cJSON提供了什么机制来释放内存?考虑到您没有明确的 malloc,我认为由于 cJSON 分配的内存而发生的任何内存泄漏,不是吗?如果是这种情况,我认为您的 c_mem_free 也应该使用 cJSON 提供的任何机制。一个故障排除步骤是编写一个在循环中分配此类 cJSON 的小程序,并尝试演示内存泄漏,首先使用 C 语言编写整个程序,然后使用 C+Fortran。
  • 我认为应该添加一个 json 标签。我不知道是哪一个,所以我不会这样做。
  • @DouglasB.Staple for ( a = 1; a &lt; 1000000; a = a + 1 ){ cJSON * nml = getnml (my_json_string, nml_name , var_name); svalue = cJSON_GetObjectItem(nml,var_name)-&gt;valuestring; // Find the string value free (nml); free (svalue); if (a % 10000 == 0) {printf("a /n");} 这不会产生泄漏。记忆保持不变。如果没有空闲(svalue),使用的内存就会增加。 cJSON 确实有一个 cJSON_free,它只使用 free。
  • cJSON 似乎在这里 github.com/DaveGamble/cJSON 并且它有 cJSON_Delete 但我找不到 getnml()。这是一个用于读取 Fortran 名称列表(在其中创建 cJSON)的包装器吗?
  • @roygvib 它是一个包装器。 fortran namelist 转换为 json,然后 cJSON 用于获取变量的值。

标签: c pointers memory fortran fortran-iso-c-binding


【解决方案1】:

作为一个竖起大拇指的规则,您不应该“释放”在代码之外分配的内存。 cJSON 也是如此。

解析对象后,树会在内存中构建,您可以访问对象、其值、更改对象等。

完成文件处理后,您可以调用 cJSON_Delete(root);

释放内存

这个程序会为你处理好一切。

如果您想在使用对象/节点时释放它们,您也可以使用 cJSON_Delete(node); 请记住,这个例程是“递归的”。因此,如果您释放一个节点,它也会释放所有子节点和兄弟节点,正如您在此处的代码中看到的那样:

/* Delete a cJSON structure. */
void cJSON_Delete(cJSON *c)
{
    cJSON *next;
    while (c)
    {
        next=c->next;
        if (!(c->type&cJSON_IsReference) && c->child) cJSON_Delete(c->child);
        if (!(c->type&cJSON_IsReference) && c->valuestring) cJSON_free(c->valuestring);
        if (!(c->type&cJSON_StringIsConst) && c->string) cJSON_free(c->string);
        cJSON_free(c);
        c=next;
    }
}

不要使用 cJSON_Free,因为 cJSON_Delete 会处理所有事情,而 cJSON_free 必须在释放结构本身之前应用于结构的内部元素,否则你会有内存泄漏。

【讨论】:

  • 使用 cJSON_Delete 在我的函数中适用于双精度和整数,但如果我在字符串函数中使用它,我最终会得到空字符串,因为字符串是作为指针传递的。
  • @byrdman1982,这是预期的行为,因为它们是指针。如果从 JSON 结构中读取字符串后需要保留该字符串,则应将其复制到字符串中。我一直问自己的问题是为什么你需要立即释放?根据定义,内存泄漏是代码中的一个问题,它导致分配的内存由于指针(例如)超出范围而变得不可访问。你确定是 cJSON 这样做吗?
  • 您认为您有内存泄漏的具体情况是什么?
猜你喜欢
  • 2014-07-24
  • 1970-01-01
  • 1970-01-01
  • 2013-10-20
  • 2012-02-26
  • 2022-06-14
  • 2016-01-01
  • 1970-01-01
  • 2010-09-07
相关资源
最近更新 更多