Clearing the pointer hurdle is a major leap to learning the C programming language. Using the malloc() function to allocate storage is central to grasping this concept. Then along comes the realloc() function, and minds are blown.
The realloc() function swallows an existing pointer, one that’s been allocated a chunk of storage, and it resizes the memory chunk. The new size can be larger. The new size can be smaller.
To demonstrate this function, the following code allocates a 2K buffer to hold a short string. This buffer is then reallocated to fit the string snuggly.
2024_08_17-Lesson-a.c
#include <stdio.h> #include <stdlib.h> #include <string.h> int main() { char string[] = "Hello there!"; char *sp; printf("Original string: %s\n",string); /* allocate way too much storage */ sp = malloc(2048); if( sp==NULL ) { fprintf(stderr,"Failed to allocate way too much storage\n"); exit(1); } /* copy the string into storage */ strcpy(sp,string); printf("String copied: '%s'\n",sp); /* reallocate (re-size) the storage */ sp = realloc(sp,strlen(string)+1); if( sp==NULL ) { fprintf(stderr,"Failed to reallocate storage\n"); exit(1); } printf("Storage reallocated: '%s'\n",sp); /* clean up */ free(sp); return(0); }
The malloc() function allocates a 2048 byte buffer, into which the existing string is copied. The string sits small in this nice, roomy buffer.
Then along comes the realloc() function, which re-sizes the allocated buffer to exactly the size of the string, plus the null character: sp = realloc(sp,strlen(string)+1);
The same pointer is used for the reallocation; no need to create a new buffer.
Here’s the output:
Original string: Hello there!
String copied: 'Hello there!'
Storage reallocated: 'Hello there!'
All this activity may seem unnecessary to save about 2K of storage for a modern computer with gigabytes of RAM. Back in the day, however, re-sizing an input buffer was something that programmers were compelled to do. Even so, re-sizing buffers is possible, probably more often to make the buffer larger than to make it smaller. In fact, for graphics programming, I’m always increasing buffers as an image is read or manipulated.
When a buffer is made larger, the new memory is uninitialized — is which is what you should expect if you work with storage in C. A question that looms is what happens when the reallocated buffer is smaller than the original? Let’s find out!
The following code modifies the original, but the reallocated buffer is only six bytes in size:
2024_08_17-Lesson-b.c
#include <stdio.h> #include <stdlib.h> #include <string.h> int main() { char string[] = "Hello there!"; char *sp; printf("Original string: %s\n",string); /* allocate way too much storage */ sp = malloc(2048); if( sp==NULL ) { fprintf(stderr,"Failed to allocate way too much storage\n"); exit(1); } /* copy the string into storage */ strcpy(sp,string); printf("String copied: '%s'\n",sp); /* reallocate (re-size) the storage */ sp = realloc(sp,6); if( sp==NULL ) { fprintf(stderr,"Failed to reallocate storage\n"); exit(1); } /* cap the string */ *(sp+5) = '\0'; printf("Storage reallocated: '%s'\n",sp); /* clean up */ free(sp); return(0); }
In this update, the realloc() function’s size is set to six bytes: sp = realloc(sp,6);
The remainder of the buffer, which contains the full original string plus up to 2K of garbage, is lopped off like the green part of a carrot. What’s left in the reallocated buffer are just the first six characters, “Hello ” (plus the space).
To make the buffer a string, I poke in the null character to replace the space: *(sp+5) = '\0';
Here’s the updated output:
Original string: Hello there!
String copied: 'Hello there!'
Storage reallocated: 'Hello'
In next week’s Lesson, I dive deep into the realloc() function, exploring what it does behind the scenes.
This has made me think that there should be (or just maybe already is) a function which takes a char pointer and reallocs it to either the actual string length, up to and including the \0, or to a specified size + 1, adding a \0 at the end.
It would be easy enough to write such a function, but the problem is validation. What happens if a random buffer is passed to the function? An overflow is possible. Even so, the concept intrigues me.
True but in a language as low level as C, and particularly in the whole area of memory allocation, the programmer is responsible for not messing up and in particular not trespassing on memory that doesn’t belong to them.
I’ve lost count of the times some vague ideas have popped into my head for streamlining common tasks in C but I hardly ever get round to doing anything about them. One of these is a string struct containing a char pointer to be malloc’ed, realloc’ed etc. as well as an int for the current size, and a few functions to work on the struct. Very vague I know but you probably understand the sort of thing I’m getting at. Obviously the concept could be expanded or generalised for any type.
A string validation function could be written. Say to confirm ASCII text and a terminating null character. But it’s tough to know for certain.