【问题标题】:pointers to structs in c指向 c 中的结构的指针
【发布时间】:2012-09-26 05:34:34
【问题描述】:
 struct TokenizerT_ {
    char* separators;
    char* tks;
    char* cur_pos;
    char* next;
  };

  typedef struct TokenizerT_ TokenizerT;

  TokenizerT *TKCreate(char *separators, char *ts) 
  { 
    TokenizerT *tokenizer;
    tokenizer = (TokenizerT*)malloc(sizeof(TokenizerT));

    //some manipulation here

    tokenizer->tks = (char*) malloc (strlen(str)* sizeof(char));
    tokenizer->tks=str;
    printf("size of tokenizer->tks is %zu\n", strlen(tokenizer->tks)); //this prints out the correct number (e.g. 7)
    return tokenizer;
  }

  int main(int argc, char **argv)
  {
    TokenizerT *tk = TKCreate(argv[1], argv[2]);
    printf("tk->tks: %zu\n", strlen(tk->tks)); //HOWEVER, this prints out the wrong number (e.g. 1)
  }

从上面的代码可以看出,我正在使用指向结构的指针。出于某种原因,我没有收到 tk->tks 的正确长度。我无法理解这一点,因为它应该与我的 TKCreate 函数中的 tks 大小相同。有人可以解释一下吗?

【问题讨论】:

    标签: c


    【解决方案1】:

    我怀疑 str 是在 TKCreate() 中定义的局部变量,它的定义未显示在您的代码 sn-p 中。如果是这样,您将分配 tokenizer->tks 以具有 str 的值,该值指向 TKCreate() 范围内的正确字符串,但在退出 TKCreate() 时,堆栈内容(包括参数和局部变量)被释放并被清除,因此当您尝试在 TKCreate() 范围之外引用该指针时,所有赌注都已关闭。

    一个合理的解决方法是动态地为 tokenizer->tks 分配存储空间,因此它在您退出 TKCreate() 后仍然存在。我看到你通过调用 malloc 来做到这一点,但是你用 str 的显式赋值覆盖了它。相反,您应该通过以下方式将 str 的内容(使用 strcpy)复制到动态分配的内存中:strcpy(tokenizer->tks, str);

    【讨论】:

    • 我刚刚添加了第二段来解释修复。看看有没有帮助。
    【解决方案2】:

    您应该将strcpy 的内容str 改为tokenizer->tks,因为当您使用赋值运算符时,您会丢失malloc 给您的指针,从而造成内存泄漏并将tokenizer->tks 指向一个局部变量,函数返回后销毁。

    所以,方法是这样的:

    tokenizer->tks = (char *)malloc ((strlen(str) + 1) * sizeof(char));
    strcpy(tokenizer->tks, str);
    

    另一件事:

    别忘了free ->tks 你释放tk本身之前。

    所以,在 printf 之后,你应该使用:

    free(tk->tks);
    free(tk);
    

    如果你的程序那么小,不释放结构和字符串(它在另一个内存位置而不是在结构的内存空间内,这就是为什么你必须释放它们)没有问题,因为在它执行之后,程序的内存无论如何都会被清除。但是如果你打算在一个完整的大程序上实现这个功能,释放内存是一个很好的操作。

    【讨论】:

      【解决方案3】:

      不清楚str是在哪里定义的,但是如果它是函数中的局部变量,你的问题很可能是超出了作用域,所以数据被覆盖了。

      您正在泄漏内存,因为您忘记使用strcpy()memcpy()memmove()str 中的值复制到分配的空间,并且您覆盖了指向新分配内存的唯一指针使用指针str。如果您复制,您将超出范围,因为您忘记为尾随的 null 和字符串分配足够的空间。您还应该检查分配是否成功。

      假代码:

      tokenizer->tks = (char*) malloc (strlen(str)* sizeof(char));
      tokenizer->tks = str;
      

      固定代码:

      size_t len = strlen(str) + 1;
      tokenizer->tks = (char *)malloc(len);
      if (tokenizer->tks == 0)
          ...error handling...
      memmove(tokenizer->tks, str, len);
      

      使用memmove()memcpy() 可以轻松胜过strcpy()(请参阅Why is Python faster than C 了解一些说明和时间)。有些人会因为在malloc() 上使用演员表而谴责你(和我);我理解他们为什么会这样争论,但我并不完全同意他们的观点(并且通常自己使用演员表)。因为sizeof(char) 的定义是 1,所以没有特别需要乘以它,尽管这样做也没有什么坏处。

      【讨论】:

        猜你喜欢
        • 2021-07-14
        • 2016-08-25
        • 1970-01-01
        • 1970-01-01
        • 2017-01-04
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多