Reviewing Dynamic Memory Allocation in C

We can find four memory management functions in the stdlib.h header file: malloc(), realloc(), calloc(), and free(). The malloc() function allocates memory from the heap. The realloc() function reallocates memory relative to a previously allocated block of memory. The calloc() function is like malloc(), but zeros out the memory that is allocated from the heap. Finally, the free() function returns a block of memory to the heap.

The malloc() function allocates a block of memory from the heap; if no memory is available, NULL is returned. Since there is no guarantee that a malloc() call will work, we should always check to see if the function returned NULL.

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

int main(void){
    
    void *memPtr = (void*)malloc(8);

    if(memPtr==NULL){
        printf("Could not allocate memory.\n");
    } else {
        printf("8 bytes allocated.\n");
    }

    free(memPtr);

    return 0;

}

The free() function accepts a pointer as an argument and returns the block of memory pointed to back to the heap.

In the next program I use bitwise operators to turn on bits in the memory block. While using bitwise operators is lots of fun, at least I think so, it isn’t the most necessary thing to know how to do. The most important thing to remember when using bitwise operators is that 0 and 1 have the same value in binary as they do in the base 10 number system. As a recap, (1 << n) will turn on the bit at position n, and the | operator basically ‘adds’ the number on the left to the  number on the right. If you’re interested in learning more, take a look at my other posts at https://aljensencprogramming.wordpress.com/tag/bitwise-operators/

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

int main(void){

    void *ptr = malloc(1);

    if(ptr!=NULL){
        //turn off all bits in the memory block
        *(char*)ptr = *(char*)ptr & 255;
        printf("%d\n", *(char*)ptr);
        
        //turn on first bit
        *(char*)ptr = *(char*)ptr | 1;
        printf("%d\n", *(char*)ptr);

        //turn on the fourth bit
        *(char*)ptr = *(char*)ptr | (1<<4);
        printf("%d\n", *(char*)ptr);
    }


    //free up the memory
    free(ptr);

    
    

    return 0;

}

Note that it isn’t necessary to explicitly cast the return value of the malloc() function; whether to cast or not to cast is a minor debate topic.

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


int main(void){


    int *ptr = malloc(4);
    int *ptr2 = (int*)malloc(4);

    *ptr = 404;
    *ptr2 = 1138;
    
    if(ptr!=NULL){
        printf("%d\n", *ptr);    
    }

    if(ptr2!=NULL){
        printf("%d\n", *ptr);
    }

    return 0;

}

When using malloc() its important to use the function to allocate the correct number of bytes. So far, we have been using magic numbers to specify the number of bytes to allocate, which is generally a bad idea. Standard procedures is to use the sizeof operator when specifying the number of bytes to allocate.

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

int main(void){

    int *iPtr = (int*)malloc(sizeof(int));

    double *dPtr = (double*)malloc(sizeof(double));


    *iPtr = 3000;
    *dPtr = 255.255;

    printf("%d \t %f\n", *iPtr, *dPtr);
    
    free(iPtr);
    free(dPtr);

    return 0;

}

Sometimes we need to increase or decrease the amount of memory allocated to a pointer, which can be done using the realloc() function. The realloc() function takes two arguments, the first argument is a pointer to the original block of memory, and the second is the new size, which can be larger or smaller than the size of the original memory block.

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

int main(void){

    int *intPtr = (int*)malloc(5*sizeof(int));
    
    *intPtr = 73;
    *(intPtr+1) = 47;
    *(intPtr+2) = 1138;
    *(intPtr+3) = 80;


    printf("%d\n", *(intPtr+1));
    printf("%d\n", *(intPtr+2));

    //resize the array
    intPtr = realloc(intPtr, 4*sizeof(int));
    
    printf("%d\n", *(intPtr+3));
    
free(intPtr);

    return 0;

}

If the size of the new memory block is smaller than the current block, the memory block remains in the same location. If the memory block is larger, either a new block in a new location will be allocated, and the contents of the old block copied over, or else if there is free consecutive memory next to the current block it will be expanded to include it.

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

int main(void){

    int *ints = (int*)malloc(10*sizeof(int));

    printf("ints is located at %p\n", ints);
    
    double *dubs = (double*)malloc(5*sizeof(double));
    
    //ints will most likely be put into a new location
    ints = realloc(ints, 20*sizeof(int));
    printf("ints is located at %p\n", ints);
    
    //memory location will remain the same
    ints = realloc(ints, 5*sizeof(int));
    printf("ints is located at %p\n", ints);

    //don't forget to free the allocated memory
    free(dubs);
    free(ints);
    
    return 0;

}

If you’re interested in learning more about C, take a look at http://www.amazon.com/Big-Als-C-Standard-ebook/dp/B00A4JGE0M/

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s