2013-08-20 2 views
1

Код ниже иногда не срабатывает при вызове buffer = (char*) realloc(buffer, allocated * sizeof(char)); (обозначен ниже), который я использую для динамического выделения пространства для char*, путем выделения 1 символа изначально и удваивания выделенной суммы каждый раз у меня уже недостаточно памяти для хранения строки.realloc терпит неудачу после нескольких вызовов, только если не отладка

У меня очень похожий код во многих других частях моего проекта, с той же политикой распределения памяти и вызовами (меняя только тип void*, я перехожу на realloc).

Я использую VS2010 для отладки проблемы, и когда я запускаю программу в режиме отладки, функция всегда завершается успешно.

Однако при вызове программы из командной строки существует хорошая вероятность, что один из вызовов realloc завершится через некоторое время с ошибкой «Чтение местоположения нарушения доступа» - хотя это не все время и происходит только после того, как функция, указанная ниже, была вызвана несколько раз, при этом многие перераспределения уже были выполнены.

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

Что я делаю неправильно?

TOKEN 
next_token_file(FILE* file, 
       STATE_MACHINE* sm, 
       STATE_MACHINE* wsssm) 
{ 
    char* buffer = (char*) malloc(sizeof(char)); 
    size_t allocated = 1; 
    size_t i = 0; 
    while(1) 
    { 
    /* 
    ... code that increments i by one and messes with sm a bit. Does nothing to the buffer. 
    */ 
     // XXX: This fails when using realloc. Why? 
     if(i + 1 >= allocated) 
     { 
      allocated = allocated << 1; 
      buffer = (char*) realloc(buffer, allocated * sizeof(char)); 
     } 
     buffer[i] = sm->current_state->state; 
    /* 
    ... more code that doesn't concern the buffer 
    */ 
    } 
    // Null-terminate string. 
    buffer[++i] = 0; 
    TOKEN t = {ret, buffer}; 
    return t; 
} 
+1

не Если это 'size_t выделено = 1;' 'size_t быть выделено = 16;'? – alk

+0

Это было бы моим предположением, либо это, либо он действительно хочет перейти от 16 символов до 2 в первом раунде (что было бы ... странно). – WhozCraig

ответ

3

Благодаря этим линиям

char* buffer = (char*) malloc(16 * sizeof(char)); 
size_t allocated = 1; 

программа сокращает buffer в течение первых 4 перераспределения. Таким образом, программа записывает в нераспределенную память от i=16, что является неопределенным поведением, поэтому все может произойти. Также это, скорее всего, разрушает управление памятью, что в свою очередь приводит к сбою realloc().

Вы хотели бы изменить эти две линии:

size_t allocated = 16; /* or = 1 if the 16 was a typo. */ 
char * buffer = malloc(allocated); 

Другие ноты:

  • sizeof(char) всегда 1.
  • Не отбрасывайте результат malloc/calloc/realloc, так как нет необходимости и не рекомендуется: https://stackoverflow.com/a/605858/694576.
  • Проверьте результаты системных вызовов.

Отсносящийся последнюю ноту, следующие изменения должны быть применены

char * buffer = malloc(allocated); 

может стать:

char * buffer = malloc(allocated); 
if (NULL == buffer) 
{ 
    /* Error handling goes here. */ 
} 

и

buffer = (char*) realloc(buffer, allocated * sizeof(char)); 

может стать:

{ 
    char * pctmp = realloc(buffer, allocated); 
    if (NULL == pctmp) 
    { 
    /* Error handling goes here. */ 
    } 
    else 
    { 
    buffer = pctmp; 
    } 
} 
+0

sizeof (char) всегда 0 ??? прости, что?! – dhein

+0

sizeof (char) даже заземлен с c99, поскольку он должен быть 1 байт, поэтому, когда вы ссылаетесь на этот sizeof (char), всегда 0? – dhein

+0

@Zaibis: Ой ... '0' была опечаткой. Исправлена. – alk

0

Я не знаю, когда вы увеличиваете или уменьшаете i. Но я бы поспорил, в соответствии с этим фрагментом, ваша проблема заключается в следующем: вы перераспределяете бесконечно, и поскольку ваш не проверяет realloc возвращает NULL, это приведет к сбою вашей программы;)

Как уже сказано, даже неплохо работает pritf's соответствуют этому, нарушая ваш блок памяти. это произойдет, перераспределив адрес памяти, который был перезаписан вне диапазона. (за исключением его UB)

Если вы пытаетесь работать, если недопустимое возвращаемое значение (то, что возвращается NULL, что может случиться, потому что u не проверяют его) Или если вы запросите нулевую область (параметр размера 0), и вы получите возвращаемый ненулевой указатель, и вы будете работать с ним. Но 2-й случай, вероятно, не будет в вашей программе;)

1

Комментарий больше, чем ответ, но у меня нет 50 баллов для комментариев.

Это:

char* buffer = (char*) malloc(16 * sizeof(char)); 

должно быть

char* buffer = (char*) malloc(1 * sizeof(char)); 

или

allocated = 16. 
+0

Не выдавайте результат «malloc/calloc/realloc», поскольку это не обязательно и не рекомендуется: http://stackoverflow.com/a/605858/694576 – alk

Смежные вопросы