【问题标题】:Problem with realloc() in C. Always hangs but compiles fineC 中 realloc() 的问题。总是挂起但编译得很好
【发布时间】:2011-03-09 09:45:09
【问题描述】:

我在使用一个打算作为字符串缓冲区的程序时遇到了一些问题,特别是这个函数旨在用字符串 cstr 重置缓冲区。如果 cstr 为 null,则需要将内容重置为空字符 '\0'。它总是挂在第二组 realloc 上,它正在调整 buf->contents 的大小我不知道为什么会这样。任何帮助都会很棒。

结构:

typedef struct strbuf {
     char   *contents;
     size_t  length;  
} StringBuffer;

调用自

strbuf_reset(sb, NULL)

这是出现问题的 strbuf_reset 函数。

StringBuffer *strbuf_reset(StringBuffer *buf, const char *cstr)
{
if(buf == NULL)
    return NULL;

StringBuffer *tempBuf = NULL ;

if(cstr == NULL)
    tempBuf = (StringBuffer*)realloc(buf,sizeof(StringBuffer) + sizeof(char));
else
    tempBuf = (StringBuffer*)realloc(buf,sizeof(buf) + strlen(cstr)*sizeof(char));

if(tempBuf == NULL)
    return NULL;

if(cstr == NULL)
    tempBuf->contents = (char*)realloc(buf->contents,sizeof(char));
else
    tempBuf->contents = (char*)realloc(buf->contents,(sizeof(buf->contents) + strlen(cstr)*sizeof(char) + 1));

if(tempBuf->contents == NULL){
    free(tempBuf);
    return NULL;
}
buf = tempBuf;

if(cstr == NULL)
   buf->contents = '\0';
else
   strcat(buf->contents,cstr);

buf->length = strlen(buf->contents);    

return buf;
 }

我认为建议的更改...

StringBuffer *strbuf_reset(StringBuffer *buf, const char *cstr)
{
if(buf == NULL)
    return NULL;

StringBuffer *tempBuf = NULL ;

if(cstr == NULL)
    tempBuf = (StringBuffer*)realloc(buf,sizeof(StringBuffer) + sizeof(char) + 10);
else
    tempBuf = (StringBuffer*)realloc(buf,sizeof(buf) + strlen(cstr)*sizeof(char)+ 1);

if(tempBuf != NULL)
    buf = tempBuf;
else
    return NULL;    

if(cstr == NULL)
    tempBuf->contents = (StringBuffer*)realloc(buf->contents,sizeof(StringBuffer) + sizeof(char) + 10);
else
    tempBuf->contents = (StringBuffer*)realloc(buf->contents,sizeof(buf) + strlen(cstr)*sizeof(char)+ 1);

if(tempBuf != NULL)
    buf->contents = tempBuf->contents;
else
    return NULL;

if(cstr == NULL)
   buf->contents = '\0';
else
   strcat(buf->contents,cstr);

buf->length = strlen(buf->contents);    

return buf;
 }

【问题讨论】:

    标签: c memory-management pointers buffer realloc


    【解决方案1】:

    你似乎不明白 realloc 做了什么。

    应该考虑的方式(至少就放大而言)是分配一个新缓冲区,将旧数据复制到其中,然后释放旧缓冲区

    然后旧指针无效,如果您稍后尝试再次使用它时遇到崩溃,这应该不足为奇。

    您应该立即将返回值分配回旧指针,因此它仍然指向有效数据。

    【讨论】:

    • 我认为将值返回到临时指针中以确保操作成功完成,然后将临时指针值复制到原始值就足够了。虽然修改后的代码仍然不起作用,这就是你的意思吗?
    • +1 小注:首先检查返回值是否!= NULL(和 errno != ENOMEM),然后分配给旧指针。否则,如果 realloc 无法分配更大的缓冲区,则会出现内存泄漏。
    • @tomekszpakowicz(我认为拼写正确......):感谢您的补充。 @Dean:您的改进版本在这方面更好。但在这一点上,你的内存分配看起来有点精神分裂。你最初是如何为 buf->contents 分配内存的?
    【解决方案2】:

    因为你要覆盖 StringBuffer 的内容,使用 realloc 是没有意义的。它不会为您节省任何内存分配,而是会复制您打算覆盖的旧数据。使用正常的 malloc 和 free。

    使用您的原始结构

    typedef struct strbuf {
      char   *contents;
      size_t  length;  
    } StringBuffer;
    

    strbuf_reset 将 buf 设置为 cstr。成功返回buf,失败返回NULL。

    StringBuffer *strbuf_reset(StringBuffer *buf, const char *cstr)
    {
      if (!buf)  return NULL;      
      if (!cstr)  cstr = "";
    
      size_t len = strlen(cstr);
      if (len > buf->length) {
        char *new_contents = malloc(len + 1);
        if (!new_contents)  return NULL;
        free(buf->contents);
        buf->contents = new_contents;
      }
      memcpy(buf->contents, cstr, len + 1);
      buf->length = len;
    
      return buf;
    }
    

    【讨论】:

    • 这绝对是最有意义的。
    • @Dean:不,它没有。天哪!现在我在问自己,为什么我会给出这样的答案。完整的解决方案。而不是仅仅回答你的问题:“不,realloc 没有问题。程序崩溃是因为......”;-P
    【解决方案3】:

    您正在为 StringBuffer 中的字符串分配额外空间。我只是假设 buf->contents 应该指向那个额外分配的空间。如果这不是真的,那么为什么要在 StringBuffer 中分配额外的空间?

    如果 buf->contents 已经指向为 StringBuffer 分配的内存,尝试重新分配它会使内存系统陷入崩溃/挂起/损坏堆的情况,因为您将重新分配一个从未分配过的指针.

    我认为结构应该如下所示,而不是尝试重新分配 buf-> 内容:

    struct StringBuffer {
        size_t length;
        char contents[1];
    };
    

    然后,您只需将字符串复制到那里,而不是重新分配 buf-> 内容,StringBuffer 的重新分配会处理所有内存。

    【讨论】:

    • 如果我只是复制其中的字符串给我一个段错误。
    猜你喜欢
    • 1970-01-01
    • 2015-08-21
    • 2016-01-21
    • 1970-01-01
    • 2014-04-18
    • 2015-10-28
    • 1970-01-01
    • 1970-01-01
    • 2021-11-15
    相关资源
    最近更新 更多