Understanding pointers with malloc and free

Pointers are really tricky in C. This is hard for many people to understand, so I wrote the following code for a good understanding:

#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 comments:

  • When I print the pointers before giving them memory, why does the pointer have a random value and a random address to point to and why is it not NULL?

  • After using malloc we can see the address where the pointer points to change and its value is NULL, so what does malloc really do?

  • After we give it a value and print it, we free it and print it again, but the values ​​and address are the same as for an array, but not for an integer, why? So what's actually free?

  • After freeing up space, we can continue to change the values ​​of the array and integer, why is this possible after free space? Don't we need to reuse malloc?

+3


source to share


3 answers


  • Because the language spec says so. The pointer's value (i.e. the address it points to) is undefined. It can point anywhere, just as it int

    can contain any value. Reading these values ​​(as with using *p

    and *a

    in the first printf

    s) is undefined behavior.

  • If you mean the data it points to 0

    , it's by accident. The allocated memory must not be cleared. For example, it can be part of a block previously allocated malloc

    and then free

    d ( free

    does not zero out memory, see point 3. below).

  • This is also accidental. When you do free

    memory, it is not zeroed out and does not need to be used immediately. It can keep old values ​​until it is used for something else (like a different distribution)

  • This is undefined behavior as well. You are writing to a memory that you no longer own. Everything can happen. The program may have crashed. By chance, it seems that you can successfully write to the array, probably because the memory is still not being used by anything else, which could have caused a more obvious runtime error.



+5


source


1. When I print pointers before giving them memory, why does the pointer have a random value and a random address to point to and why is it not NULL?

You didn't specify NULL. you simply declare it. After a pointer is declared, it can have any value.

Make NULL -

int *p = NULL; 
int *a = NULL; 

      

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

"Human" page -

void *malloc(size_t size);

      

The function malloc()

allocates size

bytes and returns a pointer to the allocated memory. The memory is not initialized. If size is 0, it malloc()

returns either NULL or a unique pointer value, which can subsequently be successfully passed to free()

.



If your allocated memory is 0, that only means randomness! The memory allocated malloc

is not released. But calloc

it does!

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

free

doesn't mean it will actually delete memory! It will tell the OS that I don't want this memory anymore, I'm using it for some other process!

You can continue to use memory a after the call free(...)

, and nothing will stop you. However, the results will be completely undefined and unpredictable. It only works by luck. This is a common programming error called " use after free " that works in many programs for literally years without "problems" - until it causes a problem.

4. After freeing up space, we can continue to change the values ​​of the array and integer, why is this possible after free space? Don't we need to reuse malloc?

This is completely undefined behavior! After freeing memory, the pointer still points to the same location in memory. It's called Dangling Pointer .

To avoid blaming the pointer, make the pointer to null

after free

!

But after freeing memory, you need to use memory facilities to use malloc

to allocate memory and use it!

+2


source


What are pointers

Pointer declarations look the same as other declarations: but don't mislead them. When pointers are declared, the keyword at the beginning declares the type of the variable that the pointer points to. The pointer itself is not of this type, it has the type of a pointer to this type. The specified pointer only points to one specific type, not all possible types. In practice, all pointers are treated as integers, but the compiler will most likely complain about assignments between incompatible types.

int *p;

      

Pointer p has no address assigned, so it still contains any random value in the memory it occupies (whatever value it was using before it was used for p). Thus, if a pointer contains the address of something, * p is equivalent to naming something directly. How do we benefit from all this? Well, immediately it bypasses the feature limitation. Imagine a function that needs to return, say, two integers representing the month and day for that month.

Summary

  • Arrays are always indexed from the zero end of history.

  • No multidimensional arrays; you are using arrays of arrays instead.

  • Pointers point to things; pointers to different types are different by themselves.

  • They have nothing to do with each other or with any other types in C; there are no automatic conversions between pointers and other types.

  • Pointers can be used to simulate a "call by function reference", but it requires a little work.

  • Incrementing or adding something to a pointer can be used to traverse arrays. To make it easier to access the array using incremental pointers, the standard guarantees that there are n elements in an array, although n does not exist, it is not an error to use its address.

Pointer arithmetic

Not only can you add an integer value to a pointer, but you can also compare or subtract two pointers of the same type. They must point to the same array, or the result is undefined. The difference between two pointers is defined as the number of array elements separating them; the type of this difference is implementation-defined and will be one of short, int or long. The following example shows how a difference can be calculated and used, but before you read it, you need to know an important point.

In the expression, the array name is converted to a pointer to the first element of the array. The only places where this is incorrect are when the array name is used in conjunction with sizeof, when a string is used to initialize the array, or when the array name is an operator address object (unary &). We have not seen any of these cases yet, they will be discussed later. Here's an example.

#include <stdio.h>
#include <stdlib.h>
#define ARSZ 10

main(){
  float fa[ARSZ], *fp1, *fp2;

  fp1 = fp2 = fa; /* address of first element */
  while(fp2 != &fa[ARSZ]){
          printf("Difference: %d\n", (int)(fp2-fp1));
          fp2++;
  }
  exit(EXIT_SUCCESS);
}

      

freed pointers

Calling free () on a pointer does not change it, only marks the memory as free. Your pointer will still point to the same location, which will hold the same value, but now the vluae can be overwritten at any time, so you shouldn't use the pointer after freeing it. To make sure it is a good idea to always point to a NULL pointer after freeing it.

+2


source







All Articles