在分配的字符串上使用strtok()?

时间:2009-10-17 11:13:38

标签: c string free malloc

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

在我的代码中,我(一般而言)

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

其中getline()是一个将char *返回给某些malloced内存的函数。 Parse(dest, line)是一个在线解析的函数,将结果存储在dest中(之前已经部分填充了其他信息)。

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

然后将它们复制到dest。

中的malloc'd char **上

现在free(line) 以及一个释放char * []在dest中的每个部分的函数,它们都出现在valgrind上:

  

“地址0x5179450是38块空闲块中的8个字节”

或类似的东西。

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

4 个答案:

答案 0 :(得分:2)

  

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

复制字符串,还是复制指针? strtok函数修改你给它的字符串,这样它就可以指向同一个字符串而不复制任何东西。当你从它获得令牌时,你必须复制它们。只要在使用任何令牌指针的情况下保持输入字符串就可以。

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

答案 1 :(得分:2)

有一个函数strdup,它分配内存然后将另一个字符串复制到其中。

答案 2 :(得分:2)

你问:

  

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

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

其次,您必须像free()malloc()那样拨打calloc()的电话号码(但realloc()可能会导致计数混乱)。

  

在我的代码中,我(一般而言)

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

除非Parse()分配它保留的空间,否则在调用{后dest结构(或更确切地说,指向dest结构内的行的指针)时,不能使用free()结构{1}}。 free()释放由getline()分配的空间,并且在此之后使用指针会产生未定义的行为。请注意,未定义的行为包括“看似工作,但只是巧合”的选项。

  

其中getline()是一个函数   将char *返回给某些malloced   内存和Parse(dest,line)是一个   在线解析的功能,   将结果存储在dest(其中   已经部分填补了,   来自其他信息)。

     

Parse()调用strtok()一个变量   在线的次数,并做一些   验证。每个令牌(指向   将strtok()返回的内容放入   进入队列直到我知道我有多少   有

请注意,strtok()返回的指针都是指向由getline()分配的单个空间块的指针。您尚未描述任何额外的内存分配。

  

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

这听起来好像是将指针从strtok()复制到一个指针数组中,但是你没有注意复制这些指针所指向的数据。

  

现在free(line)和一个函数   free是char * []的每个部分   DEST,   两人都出现在valgrind上:

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

或类似的东西。

free()的'char *[]'部分的第一个dest可能有一个指向line的指针,因此可以释放整个内存块。 dest部分的所有后续释放都试图释放malloc()未归还的地址,而valgrind正试图告诉您。然后free(line)操作失败,因为free()中指针的第一个dest已经释放了该空格。

  

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

提议的重构可能是明智的;其他人已经提到过的功能strdup()将能够整齐可靠地完成工作。

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

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

或者,请勿在致电Parse()后立即免费拨打电话。让dest记录分配的指针(line),并在释放指针数组时释放它。但是,您仍然不会释放strtok()返回的指针。

答案 3 :(得分:0)

在你的parse()中

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

对于在parse()中获取的每个子字符串,

2,相应地将其复制到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 free dest,在概念上再次:

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

4免费电话(线路)也没什么特别的,它也不会影响你的“目标”。

“dest”和“line”使用不同的内存缓冲区,因此如果愿意,您可以在步骤3之前执行步骤4。如果您按照上述步骤操作,则不会发生任何错误。好像你在代码的第2步中犯了错误。