我正在创建一个程序,通过这个过程创建一个结构:
TokenizerT *TKCreate(char *separators, char *ts) {
TokenizerT * inu = malloc(sizeof(*inu));
char * sts = malloc(strlen(ts)*sizeof(char));
char * by = malloc(lim*sizeof(char));
strcpy(by, yr);
strcpy(sts, ts);
inu->sep = by;
inu->toks = sts;
return inu;
}
我需要通过另一个函数释放struct inu,但我的函数下面似乎只释放与TokenizerT.sep相关的内存
void TKDestroy(TokenizerT *tk) {
free(tk->sep);
free(tk->toks);
}
如何释放tk.sep和tk.toks?
编辑:free(tk)导致此错误:“malloc: *对象0x7fff55662bd8的错误:释放的指针未分配 * 在malloc_error_break中设置断点以调试“
EDIT2:结构定义
struct TokenizerT_ {
char * sep;
char * toks;
};
并且
void TKDestroy(TokenizerT *tk) {
free(tk->sep);
free(tk->toks);
free(tk);
}
导致编辑1
中指定的错误相同编辑3:我还添加了我的主要方法:
int main(int argc, char **argv) {
char * arr = argv[1];
char * y = argv[2];
TokenizerT jer = *TKCreate(arr, y);
TKDestroy(&jer);
return 0;
}
答案 0 :(得分:1)
首先,“inu”的malloc似乎不正确
TokenizerT * inu = malloc(sizeof(inu));
我相信它只能获得4个字节的内存(在32位系统中)
应该是:
TokenizerT * inu = malloc(sizeof(TokenizerT ));
正如你所提到的 - “我需要释放struct inu”
我认为分配的“inu”被传递到“TKDestroy(TokenizerT * tk)”
然后:
void TKDestroy(TokenizerT *tk) {
free(tk->sep);
free(tk->toks);
free(tk) // this free is what you want to free "inu"
答案 1 :(得分:0)
您只需要反转您为分配所做的操作:
void TKDestroy(TokenizerT *tk) {
free(tk->sep); // for the 3rd malloc()
free(tk->toks); // for the 2nd malloc()
free(tk); // for the 1st malloc()
}
BTW:根据定义,您知道sizeof(char)
总是1
吗?
错误分配tk
会导致错误 - 您只是为指针分配了足够的内存,而不是整个结构。这会搞砸。
答案 2 :(得分:0)
关于你的主,替换:
TokenizerT jer = *TKCreate(arr, y);
TKDestroy(&jer);
使用:
TokenizerT *jer = TKCreate(arr, y);
TKDestroy(jer);
原因是你的create-function返回一个指针,然后你将它传递给你的destroy-function ......
答案 3 :(得分:0)
您的代码因该错误而失败的原因是&jer
是本地变量的地址。它是malloc
调用返回的非地址。
TokenizerT jer = *TKCreate(arr, y);
TKDestroy(&jer);
因此,jer
是一个局部变量。 TKCreate
返回的地址会立即被取消引用,并且会生成结构的副本。您只是无法保留TKCreate
返回的地址而且已泄露。然后,当您尝试在&jer
上自由呼叫本地变量的地址时,您的环境会正确地报告您正在向free
传递一个地址,该地址不是通过调用malloc
创建的
正如我在上一个问题中所说的,按值返回结构比使用动态分配更有意义。最重要的是,您的字符串分配不正确。您必须始终为null终止符分配足够的空间。
我会写这样的程序:
#include <stdlib.h>
#include <string.h>
typedef struct {
char *sep;
char *toks;
} TokenizerT;
TokenizerT TKCreate(const char *seps, const char *toks)
{
TokenizerT inu;
inu.sep = malloc(strlen(seps)+1);
strcpy(inu.sep, seps);
inu.toks = malloc(strlen(toks)+1);
strcpy(inu.toks, toks);
return inu;
}
void TKDestroy(TokenizerT *tk)
{
free(tk->sep);
free(tk->toks);
}
int main(int argc, char **argv)
{
TokenizerT jer = TKCreate(argv[1], argv[2]);
TKDestroy(&jer);
return 0;
}
备注:强>
sizeof(char)
是1
所以成语要求在调用malloc()
时将其作为乘法因素省略。TKCreate
的参数赋予与struct
字段相同的名称。这使得更容易理解发生了什么。更重要的是,你的代码看起来很简单,因为它忽略了其中一个参数。struct
按值返回。这在概念上更容易处理。您可能更喜欢编写辅助函数来复制字符串。如果编译器的运行时已经有一个名为strdup
的函数,那么您可以使用它。否则你可以使用这个简单的实现:
char *strdup(const char *str)
{
char *result = malloc(strlen(str)+1);
strcpy(result, str);
return result;
}
如果你只想在这样写的时候搜索null-terminator:
char *strdup(const char *str)
{
size_t len = strlen(str)+1;
char *result = malloc(len);
memcpy(result, str, len);
return result;
}
然后代码变为:
#include <stdlib.h>
#include <string.h>
char *strdup(const char *str)
{
size_t len = strlen(str)+1;
char *result = malloc(len);
memcpy(result, str, len);
return result;
}
typedef struct {
char *sep;
char *toks;
} TokenizerT;
TokenizerT TKCreate(const char *seps, const char *toks)
{
TokenizerT inu;
inu.sep = strdup(seps);
inu.toks = strdup(toks);
return inu;
}
void TKDestroy(TokenizerT *tk)
{
free(tk->sep);
free(tk->toks);
}
int main(int argc, char **argv)
{
TokenizerT jer = TKCreate(argv[1], argv[2]);
TKDestroy(&jer);
return 0;
}
如果您急于返回指向结构的指针,请按以下方式执行:
#include <stdlib.h>
#include <string.h>
char *strdup(const char *str)
{
size_t len = strlen(str)+1;
char *result = malloc(len);
memcpy(result, str, len);
return result;
}
typedef struct {
char *sep;
char *toks;
} TokenizerT;
TokenizerT *TKCreate(const char *seps, const char *toks)
{
TokenizerT *inu = malloc(sizeof *inu);
inu->sep = strdup(seps);
inu->toks = strdup(toks);
return inu;
}
void TKDestroy(TokenizerT *tk)
{
free(tk->sep);
free(tk->toks);
free(tk);
}
int main(int argc, char **argv)
{
TokenizerT *jer = TKCreate(argv[1], argv[2]);
TKDestroy(jer);
return 0;
}
请特别注意我调用TKCreate
和TKDestroy
的方式的不同。
最后,我忽略了对malloc()
调用的所有错误检查。在实际的生产代码中,你不会这样做,但为了清楚地说明,最好在这里省略它。