【问题标题】:Freeing memory after calling strtok() causes an error调用 strtok() 后释放内存会导致错误
【发布时间】:2016-01-13 08:42:57
【问题描述】:

你能帮帮我吗?我的代码进行了标记化,所以我创建了这样的代码:

  1. 我分配了一些内存,
  2. strcpy(malloced_memory, argv)
  3. 我执行strtok(mallocted_memory, ".")
  4. 试试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。但程序正在运行。

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

【问题讨论】:

    标签: c malloc strtok


    【解决方案1】:

    这一行:

    filename = malloc(sizeof(argv));
    

    应该是这样的:

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

    还有这一行:

    strk_ptr = malloc(sizeof(filename));
    

    只是造成内存泄漏,因为它后面跟着:

    strk_ptr = strtok(filename,".");
    

    你应该检查返回值:

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

    顺便说一句,strtok() 函数返回一个指针,该指针指向在初始调用中传递给它的字符串内的令牌(在您的示例中为 filename)。它不分配内存,因此不应释放其返回值(您的程序会避免这种情况,但这是一个常见错误)。虽然我对strtok() 感到不满,但我会提到您不能(直接或间接)将文字字符串传递给它以进行标记,因为它修改了字符串并且文字字符串是只读的。也就是说,这样做:strtok("sample.txt", ".") 是不行的。

    最后,这种隐式条件不是很好的形式:

    while (strk_ptr = strtok(NULL,".")) { ... }
    

    更好的是:

    while ((strk_ptr = strtok(NULL,".")) != NULL) { ... }
    

    【讨论】:

    • 他们不是在询问释放 strtok 内存,而是在询问使用 strtok 后释放内存。
    • @KeithNicholas 谢谢,改写了一下
    【解决方案2】:

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

    释放 filename 没有问题,因为它是由 ma​​lloc() 正确分配的,但是还有许多其他问题和内存泄漏。 基本上你首先为 str_ptr 分配内存:

    strk_ptr = malloc(sizeof(filename));
    

    这里ma​​lloc()返回一个存储在strk_ptr中的指针。 然后你调用 strtok() 也返回一个指针,里面 filename:

    strk_ptr = strtok(filename,".");
    

    所以您丢失了 ma​​lloc() 返回的原始指针,现在 strk_ptr 指向 filename 中的某个位置。当您调用free(str_ptr) 时,您正在释放文件名 中的内存。随后调用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是一个字符**,所以如果你想复制作为输入传递的第一个参数的内容,你必须使用argv[0],这始终是可执行文件名。

    然后,sizeof(filename) 返回指针的大小而不是内容的大小,因为 文件名 不是数组。你必须使用strlen(filename) + 1

    strtok 返回已分配的对象(文件名)内的指针,因此您不需要strk_ptr

    在循环中使用 strtok 时,请考虑采用以下方法:

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

    【讨论】:

      【解决方案3】:
       filename = malloc(strlen(argv));
       strk_ptr = malloc(sizeof(filename));
      

      strk_ptr 获得一些内存,然后你通过将 strk_ptr 指向文件名内存来保持悬空状态,然后你最终会双重释放文件名。

      所以不要malloc strk_ptr。只需将其保留为 char*,然后仅在末尾释放文件名

      【讨论】:

        【解决方案4】:
        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) */
        

        【讨论】:

          猜你喜欢
          • 2020-03-14
          • 2021-08-23
          • 2012-06-15
          • 2021-05-12
          • 2016-11-06
          • 1970-01-01
          • 1970-01-01
          • 2011-10-30
          • 1970-01-01
          相关资源
          最近更新 更多