2009-10-17 44 views
0

在malloced字符串上使用strtok有什么我应该知道的吗?在分配的字符串上使用strtok()?

在我的代码我有(笼统)

char* line=getline(); 
Parse(dest,line); 
free(line); 

其中getline()是返回一个char *一些malloc内存的功能。 和Parse(dest, line)是一个在线解析,将结果存储在dest(已从其他信息中部分填充)的函数。

Parse()在线调用strtok()可变的次数,并做一些验证。 每个标记(一个指向strtok()返回的指针)被放入一个队列中,直到我知道我有多少。

然后将它们复制到dest中的malloc'd char **上。

现在free(line) 和一个函数,它自由的炭的每个部分* []在dest,既想出上的valgrind为:

“地址0x5179450是8个字节大小的块内38自由” d“

或类似的东西。

我正在考虑重构我的代码,不直接在char **上存储标记,而是存储它们的副本(通过mallocing space == strlen(令牌)+1,然后使用strcpy())。

+0

我相信这:http://stackoverflow.com/questions/1495368/strtok-and-memory-leaks,去回答我的问题一些whay。 – 2009-10-17 11:20:48

+0

strtok在本地修改字符串,在删除符号的位置添加空值。并返回指向这些部分开始的指针 – 2009-10-17 11:31:56

回答

2

你问:

有什么我应该知道的 使用上malloced字符串的strtok?

有很多事情要注意。首先,strtok()在处理它时修改该字符串,在找到分隔符的位置插入空值('\0')。这不是分配内存的问题(可以修改!);如果您尝试将一个常量字符串传递给strtok(),则会出现问题。

其次,您必须拥有与malloc()calloc()(但realloc()可能与计数混乱)一样多的free()的呼叫。

在我的代码我有(笼统)

char* line=getline(); 
    Parse(dest,line); 
    free(line); 

除非Parse()分配它保留的空间,你不能使用dest结构(或者,更准确地说,是指针入行在dest结构内)呼叫free()free()释放由getline()分配的空间,并在此之后使用指针产生未定义的行为。请注意,未定义的行为包括'出现工作,但只能巧合'的选项。

其中函数getline()是一个函数, 返回一个char *一些malloced 存储器,和解析(目标寄存器,线)是 函数,它的在线分析, 存储在dest结果(其 已部分填写, 来自其他信息)。

解析()调用strtok()一个变量 在线次数,并做了一些 验证。每个标记(指向 的指针是由strtok()返回的)将 放入队列中,直到我知道有多少个I 。

注意,通过指针返回strtok()都是指针成getline()分配的空间单块。你还没有描述任何额外的内存分配。

然后将它们复制到dest中的malloc'd char **上。

这听起来好像您将strtok()中的指针复制到指针数组中一样,但您不会去复制这些指针指向的数据。

现在免费(线)和功能 免费的炭的每个部分* []在 DEST, 都拿出上的valgrind为:

"Address 0x5179450 is 8 bytes inside a block of size 38 free'd" 

或类似的东西。

dest的“char *[]”部分的第一free()可能有一个指针指向line,因此释放的存储器的整体块。所有对dest部分后续释放是试图释放不malloc()返回的地址,并valgrind是想告诉你。该free(line)操作失败,则是因为在dest指针的第一free()已释放该空间。

我正在考虑重构我的代码 [要]存储它们的副本[...]。

提出的重构可能是明智的;已被他人提及的功能strdup()将整齐可靠地完成工作。

需要注意的是重构之后,你仍然需要释放行,但你不会释放任何由strtok()返回的指针。它们只是指向由(由line标识)管理的空间的指针,并且将在您发布line时全部发布。

请注意,您需要释放每个分开分配的(strdup()'d)字符串以及通过dest访问的字符指针数组。

或者,在拨打Parse()后不要立即拨打电话。有dest记录分配的指针(line),释放指针数组。不过,您仍然不会发布由strtok()返回的指针。

2

然后将它们复制到dest中的malloc'd char **。

字符串被复制,或指针被复制? strtok函数修改你给它的字符串,以便它可以让你指向同一个字符串而不需要复制任何东西。当你从它得到令牌时,你必须复制它们。要么只要任何一个令牌指针在使用中,要么保持输入字符串。

许多人建议您完全避免strtok,因为它很容易出错。此外,如果您使用线程并且CRT不支持线程,strtok可能会导致您的应用程序崩溃。

+1

+1以完全避免strtok()。 – 2009-10-17 19:40:34

2

有一个功能strdup分配内存,然后复制另一个字符串到它。

+0

我现在正在调整每个令牌,然后储存。 我现在没有记忆释放错误,而且生活很好。 – 2009-10-17 12:53:44

+0

如果这回答您的问题,请点击“接受”复选标记。对于您在这里提出的其他问题,这样做会很好。如果有更好的答案出现,您可以稍后撤消它。 – 2009-10-17 14:39:22

+1

虽然不是标准的C函数。 – AnT 2009-10-17 15:59:25

0

1在您的parse()中,strtok()只在每个匹配位置写入'\ 0'。实际上这一步并不特别。使用strtok()很容易。当然它不能用于只读存储器缓冲区。

2对于parse()中获得的每个子字符串,将其相应地复制到malloc()ed缓冲区。如果我举一个简单的例子,用于存储子串,它看起来像下面的代码,说概念,虽然它可能不完全一样,你真正的代码:

 
    char **dest; 
    dest = (char**)malloc(N * sizeof(char*)); 
    for (i: 0..N-1) { 
     dest[i] = (char*)malloc(LEN); 
     strcpy(dest[i], sub_strings[i]); 
    NOTE: above 2 lines could be just one line as below 
     dest[i] = strdup(sub_string[i]); 
    } 

3免费DEST,概念再次:

 
    for (i: 0..N-1) { 
     free(dest[i]); 
    } 
    free(dest); 

4调用free(线)没有什么特别的过了,它不会影响你的“目标”甚至有点。

“dest”和“line”使用不同的内存缓冲区,因此您可以在步骤3之前执行步骤4(如果首选)。如果您执行了上述步骤,则不会发生错误。似乎你在代码的第2步中犯了错误。