21

我有一个结构

struct request {
  int code;
  char *message;
};

我想正确释放。

我有以下功能来做到这一点:

void free_request(struct request *req) {
  if (req->message != NULL) {
      free(req->message);
  }
  free(req);
  req = NULL;
}

问题是当我尝试释放使用字符串文字创建的请求时,我从编译器收到“free(): invalid pointer”/segfault 错误:

struct request *req;
req = malloc(sizeof(struct request));
req->message = "TEST";
free_request(req);

因为我想在不同的地方创建请求结构,一次使用文字(在客户端)和一次使用我从套接字读取的 *chars(在服务器端)我想知道是否有一个函数来确保我不要试图释放文字,同时仍然允许我释放我使用 malloc 创建的消息。

4

6 回答 6

24

没有标准函数可以让您知道指针是否是动态分配的。你应该在你的结构中包含一个标志来通知你自己,或者只使用动态分配的字符串(strdup在这种情况下是你的朋友)。根据您的网络设置,它可能更易于使用strdup(好吧,说实话,使用起来简单strdup)。

strdup

struct message* req;
req = malloc(sizeof *req);
req->message = strdup("TEST");
free_request(req);

带有标志:

struct message
{
    int code;
    char* message;
    bool isStatic; // replace to 'char' if bool doesn't exist
};

void free_request(struct message* req)
{
    if (!req->isStatic) free(req->message);
    free(req);
}

struct message* req;
req = malloc(sizeof *req);
req->message = "TEST";
req->isStatic = 1;
free_request(req);

此外,不要忘记在创建对象时将分配的内存归零。这可以为你省去很多麻烦。

req = malloc(sizeof *req);
memset(req, 0, sizeof *req);

那和设置reqNULLfromfree_request不会有任何效果。struct message**在函数调用之后,您需要采取或自己做。

于 2010-08-03T16:48:06.280 回答
5

无法判断您是否使用了字符串文字(好吧,您可以将字符串文字放在 GCC 创建的自定义 .section 中,然后检查字符串指针以确定它是否包含在文字的 .section 中)。然而......有一个更好的方法使用简单的编程模式。

文字分配

正常情况。对 free(req) 的调用将按预期工作:释放请求结构。

struct *req;

req = malloc(sizeof(*req));
req->message = "TEST";

使用动态字符串分配

以下some_string是您希望存储为请求消息的字符串。它可以是文字,也可以是动态分配的。这会在分配结构本身时为字符串分配内存(并在释放结构时自动释放)。

struct *req;

req = malloc(sizeof(*req)+strlen(some_string)+1);
req->message = (char *)&req[1];
strcpy(req->message, some_string);

释放

free(req);

编辑:一般情况

请注意,上面的分配方案dynamic string是通用的,即使您不知道是否some_string是文字也可以使用它。因此,一个单独的函数可以处理这两种情况,并让free()您摆脱特殊情况。

于 2010-08-03T17:22:21.387 回答
4

我建议添加一个成员来struct request指示 request::message 是否是动态分配的,并在您分配的同时设置该成员request::message,然后在释放内存之前检查它。C语言有点乱。

请注意,不仅会导致问题的字符串文字,任何指向未通过 malloc() 或 calloc() 在堆上动态分配的数据的指针都会失败,因此只需检测“如果 char指向 C 中的字符串文字” *即使它可以便携式完成也无济于事。

于 2010-08-03T16:53:31.283 回答
2

它出现段错误是因为包含的内存位置"TEST"(通常)是只读的,而不是位于堆上(通常是因为它位于程序的某些只读部分中)。仅给定一个char*指针,您将无法知道它是否指向free()-able 字符串。相反,您应该为字符分配一个缓冲区req->message并复制这些字符。

char* str = "TEST";
int len = strlen(str);
req->message = malloc(len+1);
strcpy(req->message, str);

或者,您可以按照zneakstrdup()的建议使用。

于 2010-08-03T16:47:16.960 回答
0

如果您只是想确保释放 malloc 的内存,您可以调用

realloc(req->message,(size_t)0)

如果内存库实现是健壮的,它应该可以工作。

于 2010-08-03T18:18:18.510 回答
0

看一下:

struct request *req;
req = calloc(1,sizeof(struct request));
strcpy(req->message = malloc(strlen("TEST")+1),"TEST");
free_request(req);

它严格符合ANSI C。strdup 不是 ANSI C。

req = NULL; 

是多余的。

于 2010-08-05T12:50:55.650 回答