Переместить указатель и перераспределить, C

Я пытаюсь закодировать буфер для входного файла. Буфер всегда должен содержать определенное количество данных. Если было использовано несколько байтов данных, буфер должен считывать данные из файла до тех пор, пока он снова не обретет определенный размер.

const int bufsize = 10;
int *field = malloc(bufsize*sizeof(int)); //allocate the amount of memory the buffer should contain
for(i=0;i<bufsize;++i) //initialize memory with something
    *(field+i) = i*2; 

field += 4; //Move pointer 4 units because the first 4 units were used and are no longer needed

field= realloc(field,bufsize*sizeof(int)); //resize the now smaller buffer to its original size
//...some more code were the new memory (field[6]-field[9]) are filled again...

Вот краткий пример того, как я пытаюсь это сделать в данный момент (без файлов, потому что это та часть, которая не работает), но realloc() всегда возвращает NULL. В этом примере использовались первые 4 единицы, поэтому указатель должен двигаться вперед и выделяться недостающие данные в конце памяти (чтобы она снова содержала 10 элементов). Что я делаю не так?

Я был бы очень благодарен, если бы кто-то мог мне помочь


person deadman    schedule 11.01.2015    source источник
comment
field += 4; //Move pointer 4 units because the first 4 units were used and are no longer needed и как ты собираешься free это делать? но realloc() всегда возвращает NULL, и поэтому вы должны использовать временную переменную, чтобы иметь возможность free field в случае сбоя realloc.   -  person Iharob Al Asimi    schedule 11.01.2015
comment
Вы вызываете неопределенное поведение. Адрес, который вы передаете realloc, не является адресом, возвращенным от malloc, calloc или realloc. Вы не можете передать любой адрес, который находится где-то в диапазоне динамически выделенного буфера. Это должен быть ненулевой адрес, непосредственно возвращаемый одной из этих функций без изменений.   -  person WhozCraig    schedule 11.01.2015


Ответы (2)


Вместо этого вам нужно memmove()

memmove(field, field + 4, (bufsize - 4) * sizeof(*field));

вам не нужно realloc(), потому что вы не меняете размер буфера, просто подумайте об этом.

  1. Если вы сделаете это

    field += 4;
    

    теперь вы потеряли ссылку на начало field, поэтому вы не можете даже вызвать для него free и, конечно, realloc(). Например, прочитайте комментарий WhozCraig.

  2. Делать realloc() для того же размера не имеет особого смысла.

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

    Таким образом, рекомендуемый метод

    void *pointer;
    pointer = realloc(oldPointer, oldSize + nonZeroNewSize);
    if (pointer == NULL)
        handleFailure_PerhapsFree_oldPointer();
    oldPointer = pointer;
    

Таким образом, заголовок вашего вопроса содержит ответ на него, вам нужно переместить данные со смещения 4 * sizeof(int) байтов в начало указателя, для чего memmove() является идеальным инструментом, обратите внимание, что вы также можете подумать об использовании memcpy(), но memcpy() не может справиться с перекрывающимися данными, как в вашем случае.

person Iharob Al Asimi    schedule 11.01.2015
comment
Хорошо проработано :) '+1' - person Anonymous; 11.01.2015
comment
Большое спасибо, очень хорошее объяснение, теперь я понимаю, в чем была моя ошибка - person deadman; 11.01.2015

Ваша проблема должна называться Cyclic Buffer.

Вы должны вызывать malloc() только один раз при открытии файла и один раз free() при его закрытии.

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

Ваша проблема с realloc(): вы должны передать ему тот же указатель, который ранее был возвращен из malloc() или realloc() без смещения!

person Anonymous    schedule 11.01.2015