调用strtok()后释放内存会导致错误

4

你能帮忙吗?我的代码要进行分词处理,所以我写了下面的代码:

  1. I allocate some memory,
  2. I strcpy(malloced_memory, argv)
  3. I execute strtok(mallocted_memory, ".")
  4. Try free(mallocted_memory).

    filename = malloc(strlen(argv));
    
    strcpy(filename, argv);
    strk_ptr = malloc(sizeof(filename));
    strk_ptr = strtok(filename,".");//
    i++;
    sprintf(in->file_name,"%s",strk_ptr);
    
    while(strk_ptr = strtok(NULL,"."))//
    {
        i++;
        sprintf(in->file_name,"%s.%s",in->file_name,strk_ptr);
        sprintf(in->file_ext ,"%s",strk_ptr);
    }
    free(strk_ptr);
    free(filename);
    

这段代码存在一个问题,就是我无法使用free(filename)。如果我尝试使用free(filename),程序会出现SIGTRAP错误。但是程序仍然可以正常运行。

我想要解决这个问题。我该怎么做?

4个回答

3

这行:

filename = malloc(sizeof(argv));

should be this:

filename = malloc(strlen(argv) + 1);     /* +1 for the '\0' at the end */
if (filename == NULL) { /* take some action */ }

And this line:

strk_ptr = malloc(sizeof(filename));

这段代码只会造成内存泄漏,因为它后面跟着:

strk_ptr = strtok(filename,".");

还应该检查返回值:

strk_ptr = strtok(filename,".");
if (strk_ptr == NULL) { /* take some action */ }

顺便一提,strtok()函数返回指向初始调用中传递的字符串(filename在你的例子中)中标记的指针。它不分配内存,因此其返回值不应该被释放(虽然你的程序避免了这个问题,但这是一个常见的错误)。顺便提一下,我想说的是,你不能直接或间接地将它传递给一个字面上的字符串来进行令牌化,因为它会修改该字符串,而字面上的字符串是只读的。也就是说,做如下操作:strtok("sample.txt", ".")是不行的。
最后,这种隐含条件不是很好的形式:
while (strk_ptr = strtok(NULL,".")) { ... }

更好的方式是:
while ((strk_ptr = strtok(NULL,".")) != NULL) { ... }

他们并不是在问如何释放strtok的内存,而是在问在使用完strtok后如何释放它们自己的内存。 - Keith Nicholas
@KeithNicholas 谢谢,稍微改了一下措辞。 - John Hascall

2

使用strtok()时不需要分配内存

释放filename并没有问题,因为它由malloc()正确地分配,但是还存在许多其他问题和内存泄漏。基本上,您首先要为str_ptr分配内存:

strk_ptr = malloc(sizeof(filename));

这里的malloc()返回一个指针,该指针存储在strk_ptr中。然后你调用strtok(),它也返回一个指针,在filename内部使用它:

strk_ptr = strtok(filename,".");

你丢失了由malloc()返回的原始指针,现在strk_ptr指向filename中的某个位置。当你调用free(str_ptr)时,你正在释放filename中的内存。随后调用free(filename)报告错误。解决方案很简单,不需要为strk_ptr分配内存。
我编写了一个最小化的工作代码,以向您展示如何正确使用strtok。请记住,在提问时,发布一个最小化的工作代码总是更好。
int main(int argc, char **argv) {

    char *strk_ptr;
    char *filename = malloc(strlen(argv[0]) + 1);

    strcpy(filename, argv[0]);

    printf("filename = %s, size = %zu\n", filename, sizeof(filename));

    // Do not malloc this
    //strk_ptr = malloc(strlen(filename) + 1);
    strk_ptr = strtok(filename,".");//
    printf("%s\n", strk_ptr);

    while( (strk_ptr = strtok(NULL,".")) )
    {
        printf("%s\n", strk_ptr);
    }
    free(filename);

    return 0;
}

首先,argv 是一个 char**,因此如果您想将第一个输入参数的内容复制到剪贴板中,您必须使用 argv[0],它始终是可执行文件名。
然后,sizeof(filename) 返回指针的大小而不是内容的大小,因为 filename 不是数组。您需要使用 strlen(filename) + 1strtok 在已分配对象(filename)内返回指针,因此您不需要strk_ptr 分配内存。
在循环中使用 strtok 时,请考虑采用以下方法:
   for (strk_ptr = strtok(filename, "."); strk_ptr; strk_ptr = strtok(NULL, "."))
    {
        printf("%s\n", strk_ptr);
    }

1
 filename = malloc(strlen(argv));
 strk_ptr = malloc(sizeof(filename));

strk_ptr获得一些内存,然后您通过将strk_ptr指向文件名内存来使其悬空,然后您最终会双重释放文件名。

因此,请不要malloc strk_ptr。只需将其保留为char*,然后仅在最后释放文件名


0
strk_ptr = malloc(sizeof(filename));
strk_ptr = strtok(filename,".");//
...
free(strk_ptr);

不起作用。首先,strk_ptr指向malloc的内存,但是指针立即被覆盖为其他值,因此您失去了对malloc的内存的指针,因此无法再使用free释放该内存。

编辑:

看到malloc(sizeof(filename)),我应该补充说明,您不需要为指针变量本身分配内存。声明char* strk_ptr;使编译器隐式地为该指针分配内存(即4或8个字节)。因此,您可以像使用任何其他变量一样直接使用指针,而不必free该变量的内存。

char* strk_ptr;
strk_ptr = strtok(filename,".");

或者,如果这不是你的意图,请注意sizeof(filename)并不返回字符串的长度,而只是指针变量filename的大小,通常为4或8,与filename指向的字符串无关。请参见http://www.gnu.org/software/libc/manual/html_node/String-Length.html

char string[32] = "hello, world";
char *ptr = string;
sizeof (string)
    ⇒ 32
sizeof (ptr)
    ⇒ 4  /* (on a machine with 4 byte pointers) */

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接