Broad Network


Memory Management Functions in C

Part 29 of the Complete C Course

Foreword: Memory Management Functions in C

By: Chrysanthus Date Published: 22 Jun 2024

Introduction

The size of a char is 1 byte. The size of an int is 4 bytes. The size of float is 4 bytes. The size of double is 8 bytes. The size of an array is the sum of each location in the array, all of which are the same. The size of a struct object is the sum of the sizes of the different locations in the struct, which are not necessarily the same.

While programs (processes) are running in the computer, it is not all the whole memory that is used. There are some areas in the memory that are not being used. The programmer can get a location from such an area, or can get a location for an int from such an area, or for a float from such an area. The programmer can also get locations of a whole array or struct from the area, if he/she knows the size of the array or struct in bytes. Handling such memory is memory management. The memory management predefined functions are in the library stdlib, whose header, stdlib.h has to be included into the program (preferably at the top), to allow their used.

Indeterminate Value
An object or element with indeterminate value, is an object with a number of bytes for its location, but does not yet have a type and does not yet have a practical value. Float object has 4 bytes and int object has 4 bytes. An indeterminate object of 4 bytes can be used as a float or as an int.

The calloc Function
This function creates an array from free store of a number of elements of the same size. Each byte in each element has the value, 0. The synopsis is:

    #include <stdlib.h>
    void * calloc(size_t nmemb, size_t size);

where nmemb is the number of elements in the array, and size is the width in bytes, of each element. The function returns a pointer to the allocated array space. This kind of pointer is called a pointer to void type, as can be seen from the syntax. If space could not be allocated, then the function will return a null pointer. A null pointer is a pointer whose value is decimal 0, instead of an address to a pointed object. The following program illustrates the use of the calloc() predefined function:

    #include <stdio.h>
    #include <stdlib.h>
    
    int main(int argc, char *argv[])
    {
        int *ptr = calloc(5, 4);
        ptr[0] = 0; ptr[1] = 10; ptr[2] = 20; ptr[3] = 30; ptr[4] = 40;

        for (int i=0; i<5; i++) {
            printf("%i ", *ptr);
            ++ptr;
        }
        printf("\n");

        return 0;
    }

Both stdio.h and stdlib.h have been included. stdio.h is for input and output between the operating system (keyboard/terminal) and the program. In this program, stdlib.h is for the memory management predefined functions.

The right-hand expression to the = operator of the first statement in main(), creates 5 objects (elements), each of byte-with 4. When the assignment operation of = is taking place, the five objects, become integer objects.

ptr is the pointer to the first element of the array, which at this point, is an array of integers, with 0 for each element. ptr is not a constant pointer, but can be made constant (int * const ptr), if the programmer wants to. The values of the array are accessed using ptr and the square brackets. The second line consisting of five statements in the main() function, assigns practical values to the array elements. The next code segment prints out the array values. Note that the pointer is incremented there (body), for each iteration. When a pointer is incremented, it does not point to the next byte location. It points to the next object (element) location. In the case of int, it points to the next integer, 4 bytes away. That is how the calloc() predefined function is used. The output is:

    0 10 20 30 40

Note: it was supposed to have been checked, if the pointer ptr, returned form calloc() was not null, before putting in values in the array locations.

The malloc Function

Synopsis:

    #include <stdlib.h>
    void * malloc(size_t size);

The predefined malloc() function of the stdlib library, allocates space for an object whose size is specified by the size parameter, and whose value is indeterminate. So this function can be useed to allocation memory for one char, or one int, or one float, or one double, or one struct object. The size of a struct is usually not easily determined by head. So the sozeof() operator has to be used for it; something like malloc(sizeof(employee1)), where employee1 is an object created from the struct tag such as Accountants above.

The malloc() function returns a null pointer, if space could not be allocated, or a pointer to the allocated space. If space is allocated, the pointer returned, is an example of a pointer to void, as the syntax indicates. The following program uses the malloc() function for allocations of locations of different byte widths, and put in the appropriate data type values in the locations:

    #include <stdio.h>
    #include <stdlib.h>
    
    int main(int argc, char *argv[])
    {
        char *ch = malloc(1);  
        if (ch != 0)  //check whether or not allocation was successful
            *ch = 'A';
            
        int *inte = malloc(4);
        if (inte != 0)
            *inte = 2;

        float *flt = malloc(4);
        if (flt != 0)
            *flt = 2.5;

        double *dbl = malloc(8);
        if (dbl != 0)
            *dbl = 2.5;    
    
        printf("%c %i %f %lf\n", *ch, *inte, *flt, *dbl);

        return 0;
    }

To assign a value to the particular location, use the identifier for the pointer, preceded by the indirection operator, *.

Instead of using the integers, 1, 4, 4, and 8, the types in the sizeof operator, could have been used as in: malloc(sizeof(char)), malloc(sizeof(int)), malloc(sizeof(float)), and malloc(sizeof(double)) .

The free Function

After using a location in RAM free store, the location has to be freed, so that other programs (or users) can use the same location. The library, stdlib predefined function, free() is used to free a particular location. The synopsis is:

    #include <stdlib.h>
    void free(void *ptr);

The free() function causes the space pointed to by ptr to be deallocated, that is, made available for further allocation. If ptr is a null pointer, no action occurs. Otherwise, if the argument does not match a pointer earlier returned by a memory management function, or if the space has been deallocated by a call to free or realloc, the behavior is undefined. The free function returns no value. It does not return a pointer to void. It returns void (emptiness).

When the free() function of the gcc compiler, deallocates a location (pointed object), it replaces the value of the allocation (pointed object) with zeros. Such zeros are equivalent to '\0'. The pointer still points to the pointed object, but should not be used again, for its original purpose. The following program shows the use of the free() function (read and test it):

    #include <stdio.h>
    #include <stdlib.h>
    
    int main(int argc, char *argv[])
    {
        char *ch = malloc(sizeof(char));
        if (ch != 0)
            *ch = 'A';
        free(ch);
        if (*ch == '\0') {
            printf("Deallocation for ch's object has taken place.\n");
        }
        
        int *inte = malloc(sizeof(int));
        if (inte != 0)
            *inte = 2;
        free(inte);   
        if (*inte == '\0') {
            printf("Deallocation for inte's object has taken place.\n");
        }
            
        float *flt = malloc(sizeof(float));
        if (flt != 0)
            *flt = 2.5;
        free(ch);   
        if (*flt == '\0') {
            printf("Deallocation for flt's object has taken place.\n");
        }

        return 0;
    }

The output is:

    Deallocation for ch's object has taken place.
    Deallocation for inte's object has taken place.
    Deallocation for flt's object has taken place.

The free() function can also be used to free the array allocated by the calloc() function. Note that the pointer to such an array returned, is also a pointer to void, which is not an ordinary pointer. The following program frees such an array (locations):

    #include <stdio.h>
    #include <stdlib.h>
    
    int main(int argc, char *argv[])
    {
        int *ptr = calloc(5, 4);
        ptr[0] = 0; ptr[1] = 10; ptr[2] = 20; ptr[3] = 30; ptr[4] = 40;

        for (int i=0; i<5; i++) {
            printf("%i ", *ptr);
            ++ptr;
        }
        printf("\n");
        
        free(ptr);
        
        --ptr; --ptr; --ptr; --ptr; --ptr;
        for (int i=0; i<5; i++) {
            printf("%i ", *ptr);
            ++ptr;
        }
        printf("\n");

        return 0;
    }

The output is:

    0 10 20 30 40
    munmap_chunk(): invalid pointer
    Aborted (core dumped)

When deallocation takes place with the free() function, the pointer is invalidated. The location or locations (in the case of an array), may or may not be replaced with zeros of the data type. In this output concerning the array allocated, the locations of the elements were not replaced. The second and third lines of the output are corresponding error message sent by the C execution environment.

The realloc Function

An object can be deallocated and part or all of its space immediately allocated for a new object, using the same pointer. The predefined realloc() function is used for that. The synopsis is:

    #include <stdlib.h>
    void * realloc(void *ptr, size_t size);

ptr is the pointer to the old object. size is the size of the new object, which should not be greater than that of the old object.

The realloc() function returns a pointer to the new object (which may have the same value as the pointer to the old object). The realloc() function returns a null pointer (pointer with decimal value 0), if the new object has not been allocated. In the following program, the first four bytes of an eight byte double allocated space, is reallocated for a float. The remaining four bytes become indeterminate values.

    #include <stdio.h>
    #include <stdlib.h>
    
    int main(int argc, char *argv[])
    {
        double *dbl = malloc(8);
        if (dbl != 0)
            *dbl = 3.5;    
        printf("%lf ", *dbl);
        
        float *flt = realloc(dbl, 4);
        if (flt != 0)
            *flt = 2.5;    
        printf("%f\n", *flt);

        return 0;
    }

The output is: 3.500000 2.500000



Related Links

More Related Links

Cousins

BACK NEXT

Comments