【问题标题】:Trouble freeing memory in C with other functions使用其他函数在 C 中释放内存时遇到问题
【发布时间】:2014-02-03 19:28:46
【问题描述】:

我正在创建一个程序,其中通过此过程创建结构:

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);
}

导致在 EDIT 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;
}

【问题讨论】:

  • free(tk->sep); free (tk->toks); 之后使用free(tk); 怎么样?
  • 您从未分配过 tk->sep 或 tk->toks。从这样做开始。在帖子的某处显示您的结构定义也很好。可能会产生更有洞察力的回复。
  • @gmorrow 仍然导致错误
  • 参考Jerry_J给出的答案。它包含修复代码所需的所有详细信息。 @ryyker:请注意,他实际上已经为他们两个都做了 malloc!
  • free(tk) 不是 free(toks)TokenizerT *inu = malloc(sizeof(*inu));

标签: c


【解决方案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"

【讨论】:

  • 或者更好:TokenizerT * inu = malloc(sizeof(*inu));
  • 更好:TokenizerT * inu = malloc(sizeof(*inu)); - 请注意*。这允许在不忘记基本更改的情况下更改类型。
【解决方案2】:

您只需要反转您为分配所做的操作:

void TKDestroy(TokenizerT *tk) {
    free(tk->sep);  // for the 3rd malloc()
    free(tk->toks); // for the 2nd malloc()
    free(tk);       // for the 1st malloc()
}

顺便说一句:你知道sizeof(char) 总是1 - 根据定义?


错误分配tk会导致错误-您只是为指针分配了足够的内存,而不是为整个结构分配了足够的内存。那样会搞砸的。

【讨论】:

    【解决方案3】:

    关于你的主要,替换:

    TokenizerT jer = *TKCreate(arr, y);
    TKDestroy(&jer);
    

    与:

    TokenizerT *jer = TKCreate(arr, y);
    TKDestroy(jer);
    

    原因是您的创建函数返回一个指针,然后您将其传递给您的销毁函数...

    【讨论】:

      【解决方案4】:

      您的代码因该错误而失败的原因是&jer 是局部变量的地址。是调用malloc返回的非地址。

      TokenizerT jer = *TKCreate(arr, y);
      TKDestroy(&jer);
      

      所以,jer 是一个局部变量。 TKCreate 返回的地址立即被取消引用,并制作了结构的副本。你根本没有保留TKCreate 返回的地址,它就被泄露了。然后,当您尝试在局部变量的地址 &jer 上调用 free 时,您的环境会正确报告您正在向 free 传递一个不是通过调用 malloc 创建的地址。

      正如我在上一个问题中所说,按值返回结构比使用动态分配更有意义。最重要的是,您的字符串分配执行不正确。您必须始终为空终止符分配足够的空间。

      我会这样写你的程序:

      #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;
      }
      

      注意事项:

      1. 根据定义,sizeof(char)1,因此习惯用法表示在调用 malloc() 时将其作为乘法因子省略。
      2. 我给TKCreate 指定了与struct 的字段名称相同的参数。这使得更容易理解正在发生的事情。更重要的是,您的代码看起来完全错误,因为它忽略了其中一个参数。
      3. 如上所述,struct 是按值返回的。这在概念上更容易处理。

      您可能更喜欢编写一个辅助函数来复制字符串。如果您的编译器的运行时已经有一个名为strdup 的函数,您可以使用它。否则你可以使用这个简单的实现:

      char *strdup(const char *str)
      {
          char *result = malloc(strlen(str)+1);
          strcpy(result, str);
          return result;
      }
      

      如果您只想在这样编写后搜索空终止符:

      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;
      }
      

      请特别注意我调用TKCreateTKDestroy 的方式不同。

      最后,我忽略了对malloc() 的调用的所有错误检查。在实际的生产代码中您不会这样做,但为了清楚起见,最好在此处省略它。

      【讨论】:

        猜你喜欢
        • 2018-07-09
        • 1970-01-01
        • 2022-01-11
        • 1970-01-01
        • 2011-08-28
        • 1970-01-01
        • 2016-08-07
        • 1970-01-01
        • 2017-08-19
        相关资源
        最近更新 更多