[C] Dynamic Memory (Part 3.0): Dynamic Buffering

The last two (1 and 2) articles covered the main differences between stack/heap as well as using arrays on the heap.

Now, I’m going to walk you guys through resizing these heap-allocated arrays. See, you might not always know – at compile time – how much memory you will need. Thus, we can write code that gives us just the right amount of memory. And if, for some reason, we end up needing more, we can grab some more memory. If, also, our program doesn’t need as much, we can give some back.

Okay, this time let’s write an actual program… All the necessary source can be found here.

We will start off by including the relevant headers:

#include <string.h>
#include <stdio.h>
#include <stdlib.h> /* this is where the memory functions are */

At this point, it would be wise to take a look at man realloc or man malloc and read the descriptions for malloc, realloc, and free.

From the man page:

The realloc() function changes the size  of  the  memory  block
pointed  to  by  ptr  to  size  bytes.   The  contents  will be
unchanged in the range from the start of the region up  to  the
minimum  of  the  old and new sizes.  If the new size is larger
than the old size, the added memory will  not  be  initialized.
If  ptr  is  NULL, then the call is equivalent to malloc(size),
for all values of size; if size is equal to zero,  and  ptr  is
not NULL, then the call is equivalent to free(ptr).  Unless ptr
is NULL, it must have been returned by an earlier call to  mal‐
loc(),  calloc()  or  realloc().   If  the  area pointed to was
moved, a free(ptr) is done.

Our main function begins like so:

int main(void) {
    char* s = NULL; /* start off with just a pointer */
    size_t s_len = 0; /* A pointer to nothing has a strlen of 0. */

    // ...

We initialize a char * s to NULL. Note: You should always initialize your pointers to something. It can lead to undefined behaviour if you do not.

Also, I’ve included the s_len variable to track how large our string s becomes.

int main(void) {
    // ...
    Start taking input, dynamically.   
    printf("Input a string...\n");
    do {
        s = realloc( s , ++s_len * sizeof(char) );
    } while ( ( s[ s_len - 1 ] = getchar() ) != '\n' );
    s[--s_len] = 0x00; /* remember to delimit the string! */
    End dynamic input procedure.

    // ...

While the above code may seem arcane, it’s actually quite simple.

  1. Prompt the user for input.
  2. Expand s by an extra byte. Remember that s is simple an array of characters.
  3. Store a character in the last element of s. Go to step 2 if the character isn’t an [ENTER].
  4. 0x00 (null) out the last element in the array to delimit the string.

These steps are all is needed to continuously expand a string to hold more input, more data.

int main(void) {
    // ...
    printf("\n\n%s\n", s);
    printf("s_len = %i\n", (int)s_len);
    /* Print out the ASCII codes. */
    for (size_t i = 0; i < s_len; i++)
        printf("%i ", (int)s[i]);
    /* can't forget to free! */

The next thing we do is print out s in a few ways.

And last, but certainly not least, we must free s.


That’s all there is to using realloc. Next, I’ll cover calloc and present some cool array code.



Nice post @oaktree!

Just a heads up from the realloc manpage

The realloc() function returns a pointer to the newly allocated memory, which is suitably aligned for any kind of variable and may be different from ptr, or NULL if the request fails.

realloc calls usually look like this (it all depends what your program does indeed)

   if ((aux = reallloc (s, len)) == NULL)  ERROR ("Out of memory")
   s = aux;

ERROR () prints the message and exits/returns


Yes, I should check for NULL. Note that this was demo code, so error checking was omitted to avoid any sort of confusion.

You surely would do as you have displayed.

Thanks @0x00pf!

1 Like

This topic was automatically closed after 30 days. New replies are no longer allowed.