Ошибки при использовании realloc () - PullRequest
2 голосов
/ 01 августа 2011

Я использую realloc() для динамического определения размера некоторых массивов.Потому что я писал много такого кода:

void *tmp;
if( (tmp = realloc(myobject, sizeof(object) * newsize) != NULL)
         myobject = tmp

Я думал, что сделаю код короче, сделав что-то вроде этого (глупая идея):

void GetSpace(void *ptr, size_t size_of_object, int newsize){
    void *tmp = NULL;
    if ((tmp = realloc(ptr, size_of_object * newsize) == NULL)
          //print error msg and exit
    else 
         ptr = tmp;
}
int main(){
    //This is an example
    double *mydata1 = (double *)malloc (sizeof double * 5);


    //later request more space for mydata1 
    GetSpace( mydata1, sizeof(double), 50);

}

Этоглупо, поскольку он не экономит столько строк и не делает код более читабельным, но я хотел бы знать, почему он не работает так, как я ожидаю.Когда я использую GetSpace() только для одного объекта, он работает нормально.Если я запускаю код без инициализации какого-либо объекта, с которым я вызываю функцию, он работает нормально, но когда я вызываю GetSpace() для объекта, затем помещаю в него данные и затем вызываю GetSpace() для другого объекта, я получаю стекtrace с таким сообщением

*** glibc detected *** ./a.out: realloc(): invalid old size: 0x00007fff05d96790 ***

0x00007fff05d96790 - это адрес второго массива / объекта до изменения размера.Почему это происходит?

1 Ответ

3 голосов
/ 01 августа 2011

В вашей функции GetSpace вы выделяете новый блок памяти большего размера и присваиваете адрес локальной переменной ptr.Но когда функция завершается, этот новый адрес теряется.Ваша основная программа по-прежнему имеет старое значение ptr, которое теперь указывает на неверную (освобожденную) память.

Вам необходимо вернуть новый адрес вызывающей стороне.Попробуйте это вместо этого.Обратите внимание, что параметр ptr теперь передается по ссылке, поэтому переменная вызывающей стороны обновляется.

void GetSpace(void **ptr, size_t size_of_object, int newsize){
    void *tmp = NULL;
    if ((tmp = realloc(*ptr, size_of_object * newsize) == NULL)
         //print error msg and exit
    else 
         *ptr = tmp;
}

EDIT: , как указано в комментариях, это все еще не идеально, так как вы должны выполнить грязное приведение, чтобы передать адрес вашего указателя как void**.Улучшение будет заключаться в том, чтобы возвращать новый указатель отдельно, как показано ниже:

void *GetSpace(void *ptr, size_t size_of_object, int newsize){
    void *tmp = NULL;
    if ((tmp = realloc(ptr, size_of_object * newsize) == NULL)
        //print error msg and exit
    else 
        return tmp;
}

int main(){

    ...

    //later request more space for mydata1 
    mydata1 = GetSpace( mydata1, sizeof(double), 50);
}
...