如何正确释放函数返回的结构?

How to correctly free a structure returned from a function?

我是 C 的新手,正在尝试弄清楚如何处理从函数返回的结构和引用。

比如我想做的大概就是这样。

typedef struct test_t{
    char *test_c;
} test_t;

int testFunc(test_t** output){
    test_t* testStruct = malloc(sizeof(testStruct));
    char* buf = malloc(sizeof(char)  * 5);
    strcpy(buf, "test");
    testStruct->test_c = buf;
    *output = testStruct;
    return 0;
}

int main() {
    test_t* test;
    testFunc(&test);
    printf("%s\n",test->test_c);
    free(test);
    return 0;
}

所以在 main 中我得到了测试结构。在 printf 之后(假设在 wards 之后有一些代码)我不再需要它并且想要释放它。但是如何正确地做呢?我应该先明确地解除分配 test_c 吗?但是如果没有分配呢?

结构可以像任何其他指针一样被释放。但是,您必须确保在执行此操作之前释放其所有分配的成员(否则很可能会导致结构成员的内存泄漏)。

typedef struct test_t{
    char *test_c;
} test_t;

int testFunc(test_t** output){
    test_t* testStruct = malloc(sizeof(testStruct));
    char* buf = malloc(sizeof(char)  * 5);
    strcpy(buf, "test");
    testStruct->test_c = buf;
    *output = testStruct;
    return 0;
}

int main() {
    test_t* test;
    testFunc(&test);
    printf("%s\n",test->test_c);
    free(test->test_c);
    free(test);
    return 0;
}

如果您的结构没有分配它的所有元素,您可以将它们的指针设置为 NULL,一旦传递给 free (3) 就相当于什么都不做。

But how to do it properly? Should I just deallocate test_c explicitly first? But what if it wasn't allocated?

基本经验法则:如果您编写一个函数来分配资源,请编写一个补充函数来释放它。因此,当应用于您的示例时:

void testFree(test_t* toFree) {
    free(toFree->test_c);
    free(toFree);
}

...然后...

printf("%s\n",test->test_c);
testFree(test);

如果 testFreetestFunc 一起实现和公开,调用者不需要知道您的实现细节。这些函数本身作为同一个库的一部分,将确保不变量得到正确维护。如果您切换分配方案,则无需更改调用代码。您只需修改 testFree 以配合新的 testFunc 并重新 link.

首先,您需要释放为结构中的 char 分配的内存,前提是您已经初始化了它。否则,你会得到一个错误,所以在任何释放指令之前,你应该检查保存你试图释放的 test_p 的内存位置的指针是否不是 NULL。此外,free 指令应该以*test 作为参数,而不是test。

Should I just deallocate test_c explicitly first?

是的,您必须先释放 test_c,因为如果释放 test,您将失去对 test_c 的引用。

But what if it wasn't allocated?

当您从 testFunc 返回 int 时,您可以将其用作结构分配的状态(尽管恕我直言,返回指针会更好):

int testFunc(test_t** output){
    test_t* testStruct = malloc(sizeof(testStruct));
    if (testStruct == NULL)
    /* testStruct allocation failure. */
         return -1;
    char* buf = malloc(sizeof(char)  * 5);
    if (buf == NULL) {
    /* buf allocation failure. */
         free(testStruct);
         return -1;
    }
    strcpy(buf, "test");
    testStruct->test_c = buf;
    *output = testStruct;
    return 0;
}

之后,您检查 testFunc 失败:

/* Check for allocation failure. */
if (testFunc(&test) == -1) {
    fprintf(stderr, "Allocation error");
    exit(EXIT_FAILURE);
}
/* Allocation succeeded. */
printf("%s\n",test->test_c);
free(test->test_c);
free(test)

您应该有一个分配和初始化 test_t 实例的过程。在 C++ 或其他面向对象的语言中,这将是一个构造函数。在 C 中,您必须自己滚动 - 类似于以下内容:

test_t *create_test_t(char *init_test_c)
  {
  test_t *tt;

  tt = malloc(sizeof(test_t));
  if(init_test_c != NULL)
    {
    tt->test_c = malloc(strlen(init_test_c)+1);
    strcpy(tt->test_c, init_test_c);
    }
  else
    tt->test_c = NULL;
  }

您还需要一个函数来正确删除 test_t 实例。类似于:

void destroy_test_t(test_t *tt, bool static)
  {
  free(tt->test_c);

  if(!static)
    free(tt);
  }

包含 static 参数以控制 tt 是否应该被释放。显然,您不想尝试释放指向 test_t 的静态实例的指针,在这种情况下,您会为 static 传递 TRUE。对于 test_t 的动态分配实例,例如那些使用 create_test_t 程序创建的,您将为 static.

传递 FALSE

每次需要创建或销毁 test_t 时,您都可以使用这些函数。

祝你好运。