Realloc() возвращает NULL, когда память доступна - C

  • ОС: Windows Vista (x86)
  • Компилятор: Код::Блоки

В настоящее время я пишу программу, которая открывает указанный каталог и читает его содержимое. Вместо использования printf() для отображения имен файлов сразу после их обнаружения. Я храню их в памяти и показываю позже. Я использую следующий оператор if для запуска перераспределения памяти. Я также включил объявления соответствующих переменных.

//Represents what the new index will be after the current file name is added
//to 'stack.ptr'
#define NEW_INDEX (stack.index+(strlen(ptr_dirent->d_name)))

//Contains the pointer that points to the directory's contents 'stack.ptr',
//the size of 'stack.ptr' which is 'stack.size', and the current index
//'stack.index'
struct stack
{
  int index;
  char *ptr;
  int size;
};struct stack stack;

//Sets the index to 0 and allocates 256 bytes of memory for 'stack.ptr'
stack.index = 0; stack.size = 256;
stack.ptr = malloc(sizeof(char)*stack.size);

if(NEW_INDEX > stack.size)
{
  char *temp; stack.size *= 2;
  temp = realloc(stack.ptr, sizeof(char)*stack.size);
  if (temp == NULL)
  {
    printf("ERROR: %i Bytes of memory could not be allocated.\n", stack.size);
    free(stack.ptr); closedir(dirp); return '\000';
  }
  else {stack.ptr = temp;}
}

Программа работает отлично, пока я не установил начальное значение 'stack.size' (которое является размером массива) равным 2, а не 256 (так что программа ДОЛЖНА перераспределять память). Моя программа дала сбой, потому что realloc() вернул NULL, но у меня было много доступной памяти. Я знаю, что realloc() сработал пару раз, потому что 'stack.size' был равен 16, когда произошел сбой ('stack.size' удваивается каждый раз при перераспределении памяти). Я попытался установить для «stack.size» несколько разных значений и обнаружил, что установка «stack.size» на 1 или 2 вызывает сбой, и это всегда происходит, когда «stack.size» достигает 16. Кто-нибудь может мне это объяснить. ? Я беспокоюсь, что даже если я установлю 'stack.size' на 256, моя программа может рухнуть, если каталог достаточно большой, чтобы вызвать перераспределение памяти. Также в несвязанной заметке я прочитал, что openddir("."); откроет текущий каталог, и я обнаружил, что это так, но по какой-то причине не все файлы в текущем каталоге находятся в 'stack.ptr' и файле . и .. отображаются, когда я вывожу содержимое stack.ptr в стандартный вывод.


person John Vulconshinz    schedule 18.12.2012    source источник
comment
Примечание: вы можете немного почистить свой код, так как sizeof(char) всегда будет 1   -  person Mike    schedule 19.12.2012
comment
кто-то сказал бы: необходим минимальный компилируемый пример, чтобы мы могли его попробовать... по-видимому, нет причин, по которым, если temp равен NULL, ваш код должен рухнуть (и вы специально ловите этот случай... не так ли? ?). в любом случае отладчик может помочь   -  person ShinTakezou    schedule 19.12.2012
comment
Спасибо за предложение, Майк, но я предпочитаю писать char. @ShinTakezou Я не хотел публиковать ненужный код, так как я достаточно уверен, что проблема в приведенном выше фрагменте кода. И вы правы, моя программа технически не дала сбой. Но это все еще проблема, если realloc() не может перераспределить память, когда ее более чем достаточно.   -  person John Vulconshinz    schedule 19.12.2012
comment
проблема может быть внутри, но она не проявится так легко для нас: нам нужно ее представить.   -  person ShinTakezou    schedule 19.12.2012
comment
Кроме того, вы не показываете, как вы на самом деле заполняете stack.ptr, как вы увеличиваете stack.index и т. д. Возможно, у вас есть логическая ошибка в этом коде, которая влияет на ваше управление stack.ptr. Когда вы задаете такие вопросы, вам нужно знать все, что вы делаете.   -  person Remy Lebeau    schedule 19.12.2012
comment
Кстати, почему бы не использовать std::string с std::vector или другим контейнером STL вместо того, чтобы вручную управлять всей памятью?   -  person Remy Lebeau    schedule 19.12.2012
comment
@RemyLebeau Использование std::string и std::vector может быть немного сложным в C. На самом деле это более неудобно, чем ручное управление памятью.   -  person Daniel Fischer    schedule 19.12.2012


Ответы (1)


Вы не показали нам строку, содержащую ошибку. Вероятно, это выглядит так:

strcpy(stack.ptr+stack.index, ptr_dirent->d_Name);

Проблема здесь в том, что strcpy() копирует strlen() + 1 байта. Вы пишете завершающий символ NUL за концом выделенного массива.

person Robᵩ    schedule 18.12.2012
comment
спасибо за ваш ответ, и да, это, вероятно, вызовет проблему, но я использую for(i = stack.index, j = 0; i ‹= NEW_INDEX; i++, j++) {stack.ptr[i] = ptr_dirent-›d_name[ j];} для копирования имени файла в stack.ptr, а поскольку NEW_INDEX использует strlen() для нахождения длины dirent-›d_name. Завершающий NULL не должен быть проблемой. Но я не специалист, поправьте меня, если я ошибаюсь. - person John Vulconshinz; 19.12.2012