简体   繁体   中英

C, Why does my custom free function give me the "pointer being freed was not allocated" error

I am trying to dynamically allocate an array, put some data in it, and then free it and set the array pointer to null so that it can not be accessed in the future. Also, unrelated, but I am storing the size of the array in the first element and then passing it back indexed one up, it is part of the assignment, so hopefully that doesn't confuse anyone.

If I am understanding the error correctly, I am trying to call free() on the array that my malloc'ed array was copied in to. This is not allowed because free() is not being called on the actual malloc'ed array but rather the one that's holding its values.

If this is the case, how would I fix my call of free() to only receive an array address and dereference it like free(*array); . Right now I have some mess of asteriscs and a cast and I have no idea why it works. If you know how to fix the free call into the above or just explain why what I have now works, I would greatly appreciate it. My goal is to be able to set the parameter for the custom free function to a void pointer instead of a specific data type pointer. Thanks!!

#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;
}

EDIT: Look to @JonathanLeffler comment. The issue is with alignment. I switched around some of my code but I had to index back one and not cast in my functions but instead in 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;
}

I provided a complete solution to this problem for another user. Must be a class assignment. My version is very similar to yours except I used macros instead of functions. Anyway, @Serge answer was so close. It -1 not +1.

Here what I plug into my code and it worked fine:

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

Let me explain what going on. The C allocation routines are basically doing what you are doing. They save the array size one word above the actual array. Follow link for more information on how free() works. In our version, we are saving the array size one int (2 words/4 bytes) above the actual array. Your code was wrong because the address you reference is the 3rd element and not the first. You need to pass in the address where the array allocation originated which is ((int*)(*array)) - 1 .

If you free(*array) , you don't need to *array = NULL after that.

Also, you can't cast a (void *) onto an (int *) and assign it to a (double *) .

Lastly, you can't freeArray(p); if p is a single pointer since freeArray(double ** array) has a parameter of double double-pointer.

Hopefully, this helps.

You can compare my modified code.

#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;
}


output:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM