C, почему моя произвольная функция дает мне ошибку "освобожден указатель не выделен" - PullRequest
1 голос
/ 12 февраля 2020

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

Если я правильно понимаю ошибку, я пытаюсь вызвать free() для массива, в который скопирован мой массив mallo c 'ed. Это недопустимо, потому что free() вызывается не для фактического массива mallo c 'ed, а для того, в котором хранятся его значения.

Если это так, как я могу исправить свой вызов free() только для получения адреса массива и разыменования его как free(*array);. Прямо сейчас у меня есть куча звездочек и актеров, и я понятия не имею, почему это работает. Если вы знаете, как исправить звонок в вышеперечисленном или просто объясните, почему то, что у меня сейчас работает, я был бы очень признателен. Моя цель состоит в том, чтобы иметь возможность установить для параметра произвольной свободной функции параметр указатель void вместо указанного c указателя типа данных. Спасибо !!

#include <stdlib.h>

int getSizeArray(void *array);
void * createArray(int n, int sizeOfDatatype);
void freeArray(double ** array);


int main(void){

    double * arr = createArray(10, sizeof(double));
    int size = getSizeArray(arr);

    /* using output for error checking
    for(int i = 0; i < 10; i++){
        arr[i] = i;
    }

    for(int j = 0; j < 10; j++){
        printf("%f\n", arr[j]);
    }
    */

    void* p = &arr;

    freeArray(p);

}


int getSizeArray(void *array){
    int s = ((int *) array)[-1];
    return s;
}


void * createArray(int n, int sizeOfDatatype){
    int * array = malloc((n * sizeOfDatatype) + sizeof(int));
    array[0] = n;
    return (void*) (array + 1);
}


void freeArray(double ** array){
    free(*array);
    *array = NULL;
}

РЕДАКТИРОВАТЬ: Посмотрите на комментарий @JonathanLeffler. Вопрос с выравниванием. Я переключил часть своего кода, но мне пришлось индексировать его обратно и не приводить в моих функциях, а вместо этого в main

#include <stdlib.h>

int getSizeArray(void *array);
void * createArray(int n, int sizeOfDatatype);
void freeArray(double ** array);


int main(void){

    double * arr = createArray(10, sizeof(double));
    arr = (void*) (arr + 1);
    int size = getSizeArray(arr);

    /* using output for error checking*/
    for(int i = 0; i < 10; i++){
        arr[i] = i;
    }

    for(int j = 0; j < 10; j++){
        printf("%f\n", arr[j]);
    }

    arr = (double*) (arr - 1);

    freeArray(&arr);

    for(int j = 0; j < 10; j++){
        printf("%f\n", arr[j]);
    }

}


int getSizeArray(void *array){
    int s = ((int *) array)[-1];
    return s;
}


void * createArray(int n, int sizeOfDatatype){
    int * array = malloc((n * sizeOfDatatype) + sizeof(int));
    array[0] = n;
    return array;
}


void freeArray(double ** array){
    free(*array);
    *array = NULL;
}

Ответы [ 3 ]

2 голосов
/ 12 февраля 2020

Я предоставил полное решение для этой проблемы для другого пользователя. Должно быть задание класса. Моя версия очень похожа на вашу, за исключением того, что я использовал макросы вместо функций. Во всяком случае, ответ @Serge был так близок. Это -1, а не 1.

Вот что я подключил к своему коду, и все заработало:

void freeArray(void** array)
{
    free( ((int*)(*array)) - 1 );
    *array = NULL;
}

Позвольте мне объяснить, что происходит. Процедуры выделения C в основном делают то, что вы делаете. Они сохраняют размер массива на одно слово выше фактического массива. Перейдите по ссылке для получения дополнительной информации о том, как работает free(). В нашей версии мы сохраняем размер массива на один int (2 слова / 4 байта) выше фактического массива. Ваш код неверен, потому что адрес, на который вы ссылаетесь, является третьим, а не первым. Вам нужно передать адрес, где произошло выделение массива, это ((int*)(*array)) - 1.

0 голосов
/ 12 февраля 2020

Вы можете сравнить мой модифицированный код.

#include <stdlib.h>
#include <stdio.h>

int getSizeArray(void *array);
void * createArray(int n, int sizeOfDatatype);
void freeArray(void ** array);


int main(void){

    double * arr = (double *)createArray(10, sizeof(double));
    int size = getSizeArray(arr);

    printf("size of arr %d\n", size);

    // using output for error checking
    for(int i = 0; i < 10; i++){
        arr[i] = i;
    }

    for(int j = 0; j < 10; j++){
        printf("%f\n", arr[j]);
    }


    void ** p = (void **)&arr;

    freeArray(p);
    printf("del arr, then arr = %u\n",(unsigned)arr);

}


int getSizeArray(void *array){
    int s = ((int *) array)[-1];
    return s;
}


void * createArray(int n, int sizeOfDatatype){
    int * array = (int*)malloc((n * sizeOfDatatype) + sizeof(int));
    array[0] = n;
    return (void*) (array + 1);
}


void freeArray(void ** array){
    free(((int*)*array)-1);
    *array = NULL;
}


вывод:

size of arr 10
0.000000
1.000000
2.000000
3.000000
4.000000
5.000000
6.000000
7.000000
8.000000
9.000000
del arr, then arr = 0
0 голосов
/ 12 февраля 2020

Если вы free(*array), вам не нужно *array = NULL после этого.

Кроме того, вы не можете наложить (void *) на (int *) и назначить его на (double *).

Наконец, вы не можете freeArray(p);, если p является одиночный указатель, поскольку freeArray(double ** array) имеет параметр двойного двойного указателя.

Надеюсь, это поможет.

...