Search code examples
carrayspointersmallocfree

Understanding of pointers with malloc and free


Pointers are a really tricky thing in C. For a lot of people is hard to understand it, so for a good understanding I wrote following code:

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

int main(int argc, char *argv[])
{
    int *p; // pointer -> will be dynamic allocated
    int *a; // array -> will be dynamic allocated

    // print before allocate memory (1)
    printf("&p: %p\tp: %p\t*p: %d\n", &p, p, *p);
    printf("&a: %p\ta: %p\t*a: %d\n", &a, a, *a);
    printf("\n");

    // allocate memory (2)
    p = (int *)malloc(sizeof(int));
    a = (int *)malloc(sizeof(int) * 10);

    // print after allocate, but before give a value to poinetrs (3)
    printf("&p: %p\tp: %p\t*p: %d\n", &p, p, *p);
    printf("&a: %p\ta: %p\t*a: %d\n", &a, a, *a);
    printf("\n");

    // give a value to poinetrs (4)
    *p = 1;
    for (int i = 0; i < 10; i++) { a[i] = i; }

    // print after we gave a value to pointers (5)
    printf("&p: %p\tp: %p\t*p: %d\n", &p, p, *p);
    printf("&a: %p\ta: %p\t*a: ", &a, a);
    // because a is an array we must use a loop for print 
    for (int i = 0; i < 10; i++) { printf("%d ", a[i]); }
    printf("\n");
    printf("\n");

    // free pointers (6)
    free(p);
    free(a);

    // print pointers after free (7)
    printf("&p: %p\tp: %p\t*p: %d\n", &p, p, *p);
    printf("&a: %p\ta: %p\t*a: ", &a, a);
    // because a is an array we must use a loop for print 
    for (int i = 0; i < 10; i++) { printf("%d ", a[i]); }
    printf("\n");
    printf("\n");

    // try to change values after free (8)
    *p = 12;
    for (int i = 0; i < 10; i++) { a[i] = 3; }

    // print after (8)
    printf("&p: %p\tp: %p\t*p: %d\n", &p, p, *p);
    printf("&a: %p\ta: %p\t*a: ", &a, a);
    // because a is an array we must use a loop for print 
    for (int i = 0; i < 10; i++) { printf("%d ", a[i]); }
    printf("\n");
    printf("\n");

    return 0;
}

Output:

&p: 0xbfe5db64  p: 0xbfe5dc24   *p: -1075452506
&a: 0xbfe5db68  a: 0xbfe5dc2c   *a: -1075452502

&p: 0xbfe5db64  p: 0x8716008    *p: 0
&a: 0xbfe5db68  a: 0x8716018    *a: 0

&p: 0xbfe5db64  p: 0x8716008    *p: 1
&a: 0xbfe5db68  a: 0x8716018    *a: 0 1 2 3 4 5 6 7 8 9 

&p: 0xbfe5db64  p: 0x8716008    *p: 0
&a: 0xbfe5db68  a: 0x8716018    *a: 0 1 2 3 4 5 6 7 8 9 

&p: 0xbfe5db64  p: 0x8716008    *p: 12
&a: 0xbfe5db68  a: 0x8716018    *a: 3 3 3 3 3 3 3 3 3 3 

Now, questions and observations:

  1. When I print pointers before give memory for it, why pointer have a random value and a random address to point to it and why it isn't NULL?

  2. After we use malloc, we can see the address where pointer points to changed and its value is NULL, so what malloc really does?

  3. After we give a value to it and print it, we free it and print it again, but values and address are same as behind for array, but not for the integer, why? So what free really does?

  4. After we freed space, we can continue to change values of array and integer, why is this possible after free space? We don't need to reuse malloc?


Solution

    1. Because the language specification says so. The value of the pointer (i.e. the address it points to) is indeterminate. It can point anywhere, just like an int could hold any value. Reading those values, (as you do with *p and *a in the first printfs) is actually undefined behaviour.

    2. If you mean the data it points to is 0, that is by chance. The memory allocated does not have to be zeroed out. For example, it could be part of a block previously allocated with malloc and then freed (free doesn't zero out the memory, see point 3. below.)

    3. That is also by chance. When you free the memory, it is not zeroed out, and it does not have to be used immediately. It can keep storing old values until it is used for something else (for instance, by another allocation)

    4. That is also undefined behaviour. You are writing to memory you no longer own. Anything can happen. The program could have crashed. By chance, it seems like you can successfully write to the array, probable because the memory is still not used by anything else that would cause a more apparent run time error.