简体   繁体   中英

C - Cant free char** pointer memory - error CrtIsValidHeapPointer

I have a function which builds an array of strings (char*) .
After I finished using the array I want to free its memory but then I get a CrtIsValidHeapPointer Error.

Code:

int main(int argc, char * argv[])
{
    char** arr = NULL;

    creating_array(&arr);    // Building the array

    //free each string memory
    for (size_t i = 0; i < 4; i++)
    {
        free(arr[i]);
    }

    // until here everything works fine :)

    //free the array memory    
    free(arr);        // Error CrtIsValidHeapPointer

    return 0;
}

void creating_array(char*** pArr)
{
    char** arr = (char**)malloc(4);
    arr[0] = (char*)malloc(5 * sizeof(char));
    strcpy(arr[0], "aaaa");
    arr[1] = (char*)malloc(5 * sizeof(char));
    strcpy(arr[1], "bbbb");
    arr[2] = (char*)malloc(5 * sizeof(char));
    strcpy(arr[2], "cccc");
    arr[3] = (char*)malloc(5 * sizeof(char));
    strcpy(arr[3], "dddd");

    *pArr = arr;
}

Why does it happen?

Please try, in creating_array

char **arr ;
arr=(char **) calloc( 4 , sizeof(char *));

Here is the working code. It compiles and runs now.

Generally after freeing a pointer, people set it to NULL to avoid confusion (so that any time a pointer is not null it points to valid memory). That avoids bugs. Also it is legal to free(NULL) , so you don't get into very severe and hard-to- debug problems that happen if you double-free an address.

One important point, is that in this case, the parenthesis in this case (*pArr)[2] are important, to override the operator precedence in C. If you try *pArr[2] it assumes you mean to de-reference the pointer stored at element [2]. (*pArr)[2] means return element at element to from the the location at the address pointed to by pArr . The reason C assumes the other case and that you need parens in this case is that the other use is much much more common, so it is convenient.

Note: ALWAYS check return values for malloc() and function calls and have a strategy to catch and log errors. Otherwise as you start writing bigger programs you will find them extremely difficult, troublesome or nearly impossible to debug.

Another thing is to create named constants instead of literals, because then it is clear what the number is and how it is used, and if that number is needed in more than one place it can be changed in one place. It makes the program easier to read and understand.

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

#define STRING_COUNT 4

char **create_array(char ***pArr);

int 
main()
{
    char **arr = NULL;

    if (create_array(&arr) == NULL) {
        fprintf(stderr, "out of memory - exiting\n");
        return -1;
    }
    for (size_t i = 0; i < STRING_COUNT; i++) {
        printf("%s\n", arr[i]);
    }
    for (size_t i = 0; i < STRING_COUNT; i++) {
        free(arr[i]);
        arr[i] = NULL;
    }
    free(arr);      
    return 0;
}

char **
create_array(char ***pArr)
{
    if ((*pArr = malloc(STRING_COUNT * sizeof (char **))) == NULL) {
       return NULL;
    }
    if (((*pArr)[0] = strdup("aaaa")) == NULL) {
        return NULL;
    }
    if (((*pArr)[1] = strdup("bbbb")) == NULL) {
        free((*pArr)[0]);
        *pArr[0] = NULL;
        return NULL;
    }
    if (((*pArr)[2] = strdup("bbbb")) == NULL) {
        free((*pArr)[0]);
        *pArr[0] = NULL;
        free((*pArr)[1]);
        *pArr[1] = NULL;
        return NULL;
    }
    if (((*pArr)[3]= strdup("bbbb")) == NULL) {
        free((*pArr)[0]);
        *pArr[0] = NULL;
        free((*pArr)[2]);
        *pArr[1] = NULL;
        free((*pArr)[2]);
        *pArr[2] = NULL;
        return NULL;
    }
    return *pArr;

}

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