简体   繁体   中英

Does Freeing a Pointer Free the Memory it References?

I'm currently working through Zed Shaw's Learn C the Hard Way tutorials and I'm trying to understand what is on the stack and what is on the heap in the following example, and how free() is working.

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

/** our old friend die from ex17. */
void die(const char *message)
{
    if(errno) {
        perror(message);
    } else { 
        printf("ERROR: %s\n",message);
    }
    exit(1);
}

// a typedef creates a fake type, 
// in this case for a function pointer
typedef int (*compare_cb)(int a, int b);
// by declaring this pointer to a function
// we can use this like an int/char etc. in a function's arguments
/**
* A classic bubble sort function that uses the
* compare_cb to do the sorting.
*/
int *bubble_sort(int *numbers, int count, compare_cb cmp)
{
    int temp = 0;
    int i = 0;
    int j = 0;
    int *target = malloc(count * sizeof(int));

    if(!target) die("Memory error.");

    memcpy(target, numbers, count * sizeof(int));

    for(i = 0; i < count; i++) {
        for(j = 0; j < count - 1; j++){
            if(cmp(target[j], target[j+1]) > 0) {
                temp = target[j+1];
                target[j+1] = target[j];
                target[j] = temp;

            }
        }
    }
    return target;  // returns address of target(I think)
}                   // target will persist even after function 
                    // exit because we created on the heap (memcopy)
                    // so what happens if we run more than once?

int sorted_order(int a, int b)
{
    return a - b;
}

int reverse_order(int a, int b)
{
    return b - a;
}

int strange_order(int a, int b)
{
    if(a == 0 || b == 0) {
        return 0;
    } else {
        return a % b;
    }
}

/** 
 * used to test that we are sorting things correctly
 * by doing the sort and printing it out.
 */
void test_sorting(int *numbers, int count, compare_cb cmp)
{
    int i = 0;
    int *sorted = bubble_sort(numbers, count, cmp);

    if(!sorted) die("failed to sort as requested.");

    for(i = 0; i < count; i++){
        printf("%d ", sorted[i]);
    }
    printf("\n");

    free(sorted);
    sorted = NULL; 
}

int main(int argc, char *argv[])
{
    if(argc < 2) die("USAGE: ex18 4 3 1 5 6");

    int count = argc - 1;
    int i = 0;
    char **inputs = argv + 1;

    int *numbers = malloc(count * sizeof(int));
    if(!numbers) die("Memory error.");

    for(i = 0; i < count; i++) {
        numbers[i] = atoi(inputs[i]);
    }
    test_sorting(numbers, count, sorted_order);
    test_sorting(numbers, count, reverse_order);
    test_sorting(numbers, count, strange_order);

    free(numbers);
    numbers = NULL;

    return 0;
}

In the function bubble_sort , an array of ints target is created on the heap. My understanding is that since this is on the heap, it will persist after the function exits.

int *target = malloc(count * sizeof(int));

the function then returns target

return target;

I believe that means that the function returns the address of target

later, in test_sorting the result of the bubble_sort function is passed

int *sorted = bubble_sort(numbers, count, cmp);

so, if I'm right, the pointer sorted has been set to the same address as target

at the end of test_sorting *sorted is freed but the data pointed to by *target is never freed. But when I run the program in Valgrind I get no memory leaks, so this can't be true.

Am I right, then, in saying that when I free a pointer, the thing it points to is freed? I think probably not... I can't find any reference to this online so I'm assuming I'm mistaken at some point above, but I can't see where.

You're not running free to release the memory used to store the pointer value, but to free up the chunk of memory that pointer references, and the pointers sorted and target reference the same chunk of memory (within scope). When you free that memory, neither pointer can be legally dereferenced to that chunk.

Does Freeing a Pointer Free the Memory it References?

Yes. Quoting from: Usage of free :

When we want to free a memory chunk previously allocated by malloc() , we use the free function. This function accepts a char pointer to a previously allocated memory chunk, and frees it - that is, adds it to the list of free memory chunks, that may be re-allocated. Several notes about free() :

  • The size of the chunk was stored by malloc() previously in its memory map, and that is how free() knows how many bytes to free.
  • The freed memory is not being cleared or erased in any manner. This is why accessing memory that was just freed often does not cause a crash - any data in it is still the same as before calling free() .

  • The free() function cannot nullify pointers to the given memory chunk that might still exist in our program. After we call free() , it is up to us (the programmers) not to try and dereference pointers that still point to that memory chunk. Such pointers are known as 'dangling pointers' - they point to memory that was already freed, and thus they should NOT be dereferenced again, unless they are assigned the address of a different (not-freed) memory chunk.

As you can see, free() only marks the memory chunk as free - there is no enforcement of this freeing operation.

The pointer itself is allocated on the stack and - as you already mentioned - holds an address. You also return the pointer by value and pass it by value unless you pass a pointer to the pointer. Malloc allocates memory somewhere and returns a pointer to this location(the address). If you don't want this memory to become unusable, you have to tell the system that you don't need it any longer later. Therefore you pass the address (ie the pointer) of the previously allocated chuck to free. This call actually frees the memory pointed to. The pointer itself will go out of scope when the function returns.

Yes, sorted and target will have the same address.
You can see this by printing both values.
In bubble_sort: printf("target address %X\\n", target);
In test_sorting: printf("sorted address %X\\n", sorted);

These should be the same, so the address is returned, then freed.

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