Проблема с realloc () в C. Всегда зависает, но компилируется нормально - PullRequest
3 голосов
/ 29 июня 2010

У меня возникли проблемы с программой, предназначенной для буфера строк, в частности, эта функция предназначена для сброса буфера с помощью строки cstr.Если cstr равен нулю, то содержимое должно быть сброшено в пустой символ '\ 0'.Он всегда висит на втором наборе realloc, где он изменяет размер buf-> content. Я понятия не имею, почему это так.Любая помощь будет потрясающей.

Структура:

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

Ответы [ 3 ]

7 голосов
/ 29 июня 2010

Вы, кажется, не понимаете, что делает realloc.

То, как вы должны думать об этом (по крайней мере, в части увеличения), заключается в том, что он выделяет новый буфер, копирует в него старые данные, а затем освобождает старые буфер .

Тогда старый указатель недействителен , и он не должен удивлять, если вы получаете сбой при попытке использовать его позже.

Вы должны немедленно присвоить возвращаемое значение старому указателю, чтобы он по-прежнему указывал на действительные данные.

1 голос
/ 29 июня 2010

Поскольку вы собираетесь перезаписывать содержимое StringBuffer, использование realloc не имеет смысла. Это не сэкономит вам никакого выделения памяти, но вместо этого скопирует старые данные, которые вы намереваетесь переписать. Используйте обычный malloc и бесплатный.

С вашей оригинальной структурой

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;
}
1 голос
/ 29 июня 2010

Вы выделяете дополнительное место для строки в StringBuffer. Я просто предположил, что buf-> content должен указывать на это дополнительное выделенное пространство. Если это не так, то почему дополнительное пространство выделяется в StringBuffer?

Если содержимое buf-> уже указывает на память, которая была выделена для StringBuffer, попытка перераспределения приведет к тому, что система памяти попадет в ситуацию кучи аварийного завершения / зависания / повреждения, потому что вы будете повторно использовать указатель, который никогда не выделялся .

Вместо того, чтобы пытаться перераспределить содержимое buf-> содержимого, я думаю, что структура должна выглядеть следующим образом:

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

Тогда вместо переопределения содержимого buf-> просто скопируйте туда строку, а realloc для StringBuffer позаботится обо всей памяти.

...