The C language woefully lacks a trim() or similar string manipulation function. Rather than let it flail in absent envy, your task for this month’s Exercise is to code such a function. The goal is to remove whitespace characters from either end of a string.
I can think of a number of ways to craft a trim() function. My approach is to pass the string to the function, then return a modified string, leaving the original string untouched. This modified string is allocated in the function, so the new string’s address is returned. Here’s the prototype:
char *trim(const char *s)
This function calls two other functions that do the trimming: rtrim() and ltrim(), which remove whitespace from the right and left sides of a string, respectively. I favor this approach as it not only allows me to piece out the solution, but the two functions are available separately as left-right string trimming functions. Again, such functions are readily found in other programming languages.
Aside from calling rtrim() and ltrim(), the trim() function confirms that the string passed isn’t NULL. It compares the results from rtrim() and ltrim() to ensure that an empty string doesn’t result, which must be specially handled. Otherwise, storage is allocated for the new string and characters copied into it.
I also made a few modifications to the main() function: A test is made for the NULL return from the trim() function. Upon success, the pointer returned is freed. (If not, the allocated memory goes untracked.)
Here is my solution:
2026_04-Exercise.c
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> /* find the first non-space character on the right */ char *rtrim(char *s) { char *right = NULL; right = s+strlen(s)-1; while( isspace(*right) ) { right--; } return(right); } /* find the first non-space character on the left */ char *ltrim(char *s) { char *left = NULL; left = s; while( isspace(*left) ) { if( *left=='\0' ) break; left++; } return(left); } /* trim spaces from the left and right of a string; return the new string */ char *trim(char *s) { char *trimmed,*front,*back; int offset; /* test for NULL pointer */ if( s==NULL ) return(s); /* return NULL pointer */ /* find the ends */ back = rtrim(s); front = ltrim(s); /* allocate storage */ if( back>front ) /* string contains some text */ trimmed = malloc( sizeof(char) * (back-front) + 1 ); else /* string is empty or all spaces */ trimmed = malloc( sizeof(char) * 1 ); /* create the trimmed string */ if( trimmed!=NULL ) { /* empty string test */ if( sizeof(trimmed)==1 ) { *trimmed = '\0'; /* empty string */ } else { /* copy the center */ offset = 0; while( front<=back ) { *(trimmed+offset) = *front; front++; offset++; } *(trimmed+offset)='\0'; } } return(trimmed); } int main() { char *sample[] = { " one ", "\ttwo\n", "", " ", "a", " x ", NULL, " \t three \n", "four", " five", "six ", " seven eight " }; int size,x; char *t; /* obtain array size */ size = sizeof(sample)/sizeof(sample[0]); /* output trimmed strings */ for( x=0; x<size; x++ ) { printf("'%s' => ",sample[x]); t = trim(sample[x]); if( t==NULL ) { printf("Bad string\n"); } else { printf("'%s'\n",t); free(t); } } return 0; }
Both the rtrim() and ltrim() functions use the isspace() function to check for spaces, prototyped in the chtype.h header file. This function is used in a while loop to locate spaces at the start and end of the string. Both functions return a pointer to the first non-space character, right and left, in the string.
In the trim() function, an initial test is made to determine whether a NULL pointer was passed. If so, the same pointer is returned. For all other strings, the rtrim() and ltrim() functions are called. Each function returns a pointer holding the address of the first non-space characters in the string, back and front.
A test is made to check whether the back pointer is greater than the front pointer. If so, the string contains some text. Storage is allocated for the text, plus one for the null character.
When the back pointer is less than or equal to the front pointer, the string is either empty or contains all whitespace characters. If so, storage is allocated for only a single character, which creates an empty string.
The next part of the function fills the trimmed string with characters. If the size of trimmed is one byte, the null character is set. Otherwise, characters are copied from the passed string (s) to the allocated string (trimmed). The string is capped with a null character and returned.
Here’s a sample run of my solution:
' one ' => 'one' ' two ' => 'two' '' => '' ' ' => '' 'a' => 'a' ' x ' => 'x' '(null)' => Bad string ' three ' => 'three' 'four' => 'four' ' five' => 'five' 'six ' => 'six'
This exercise proved more difficult than I originally thought. In fact, my first solution didn’t consider the final sample string where spaces are found in the middle. My second solution didn’t account for empty strings or strings composed entirely of spaces. The key for me was first coding the rtrim() and ltrim() functions, which made the rest of the process easier.
I hope that your solution met with success.