nurtul
nurtul

Reputation: 408

C - Storing pointers with malloc() in an array, can't free() them afterwards

I want to store pointers that have been allocated using malloc() in an array and then free all of them after. However even though the program doesn't complain it doesn't work. Below cleanMemManager() won't actually free the memory as when tested inside main() the char* pointer is not NULL and it will print ???.

code:

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

void **ptrList = NULL;

void tfree(void** ptr)
{
    free(*ptr);
    *ptr = NULL;
}

void* talloc(int size)
{
    void* ptr = malloc(size);
    ptrList[0] = ptr;   ///No clue if this actually does what I think it does
    return ptrList[0];
}

void initMemManager()
{
    ptrList = (void**)malloc(sizeof(void**) * 3);
    memset(ptrList, 0, sizeof(void**) * 3);
}

void cleanMemManager()
{
    tfree(&ptrList[0]); //Doesn't free the right pointer it seems
}

int main()
{
    initMemManager();
    char* ptr = (char*)talloc(3);
    cleanMemManager();

    if (ptr != NULL) //This will trigger and I'm not expecting it to
        printf("???");

    getchar();
    return 0;
}

I don't understand the syntax to use for this, does the pointer not actually get touched at all? What is it freeing then since it doesn't throw any errors?

Upvotes: 2

Views: 1318

Answers (2)

Eric Postpischil
Eric Postpischil

Reputation: 222763

In main, char *ptr = (char*)talloc(3); declares ptr to be a local variable. It contains a copy of the value returned by talloc, and none of your subroutines know about ptr or where it is. So none of them change the value of ptr. Thus, when you reach if (ptr != NULL), the value of ptr has not changed.

Additionally:

  • In initMemManager, you should use sizeof(void *) in two places where you have sizeof(void**). In these places, you are allocating and copying void * objects, not void ** objects.

  • It looks like you are trying to implement a sort of smart memory manager that automatically sets pointers to NULL when they are freed. To do that in C, you would have to give up having copies of pointers. For example, ptr is a copy of ptrList[0], but tfree only sets whichever copy it is passed to NULL. We could give advice on building such a system, but it would quickly become cumbersome—your memory manager needs to keep a database of pointers and their copies (and pointers derived from them, as by doing array arithmetic). Or you have to refer to everything indirectly through that ptrList array, which adds some mess to your source code. Unfortunately, C is not a good language for this.

Upvotes: 5

PythEch
PythEch

Reputation: 952

Freeing doesn't guarantee that pointers pointing to the allocated block will be set to NULL. If you actually try doing

if (ptrList[0] != NULL)
      printf("ptrList[0] != NULL");

you will see that the program won't output and if you remove the cleanMemManager() function call, it will output. This means tfree function is working as intended, it's freeing the memory that was allocated.

Now as to why ptr variable being not set to NULL, it's simply because ptr is still storing the old address. cleanMemManager() has no way of mutating the variable ptr. This is commonly called dangling pointer or use after free.

Also free() doesn't clean/zero out the the allocated space, the block is simply marked as "free". The data will most likely remain in the memory for a moment until the free block is overwritten by another malloc request.

Upvotes: 3

Related Questions