You are on page 1of 17

Giulio" using the $ sign for padding.

Line 4 of the output (Listing 6-17 ) shows that STR_copy_string()


doesnt count the padding in its returned value, as it only counts the 6 letters of "Giulio" .
The second example in lines 8 to 10 of the code uses a NULL character for padding. This makes the
destination string look exactly as the source string when you display it in line 7 of the output because the first
NULL is interpreted as a terminator and the other four NULL s (the remaining three of padding plus the original
terminator) are ignored. Obviously, all 10 characters of the original str (plus the terminating NULL ) are still
occupied by the updated string.
The third example in lines 12 to 14 of the code attempts to overwrite the 10 characters of str with the
13 characters of " Giulio Zambon " . Line 10 of the output shows that the string is truncated. Obviously, no
padding is needed.
The fourth example in lines 16 to 18 of the code copies an empty string to str . Its purpose is to show
that, when you do so, the destination string is filled with the padding character, as shown in line 13 of the
output.
Finally, the fifth example in lines 20 to 22 of the code shows what happens when you attempt to copy a
NULL string. Perhaps not surprisingly, str_copy_string() leaves the destination string unchanged, as shown
in line 16 of the output.
The macro STR_copy_string() is only an alias for the corresponding function:
#define STR_copy_string(str, st, pad) str_copy_string(str, st, pad)
The code of str_copy_string() is shown in Listing 6-19 .
Listing 6-19. str_copy_string()
1. //------------------------------------------------------------- str_copy_string
2. size_t str_copy_string(Str *str, char *s, char pad) {
3. #if STR_LOG
4. if (pad == '\0') printf("=== str_copy_string: %p \"%s\" '\\0'\n", str, s);
5. else printf("=== str_copy_string: \"%s\" '%c' -> %p\n", s, pad, str);
6. #endif
7. if (str == NULL) {
8. STR_crash("str_copy_string: destination Str pointer NULL");
9. }
10. else if ((str)->s == NULL) {
11. STR_crash("str_copy_string: destination string pointer NULL");
12. }
13. size_t n_copy = 0;
14. if (s != NULL) {
CHAPTER 6 STRING UTILITIES
158
15. size_t len = strlen(s);
16. size_t space = str->size - sizeof(Str);
17. if (space > 0) {
18. space--;
19. n_copy = (len > space) ? space : len;
20. if (n_copy > 0) (void)memcpy(str->s, s, n_copy);
21. if (n_copy < space) (void)memset(&str->s[n_copy], pad, space - n_copy);
22. str->s[space] = '\0';
23. }
24. }
25. return n_copy;
26. } // str_copy_string
After checking that the destination is a proper string (lines 7 to 12), it calculates the length of the source
string (line 15) and the space allocated for a C string in the destination Str (line 16). Note that, if space > 0
(condition checked in line 17), it is at least 2 because str_new() doesnt allow the allocation of empty strings.
Therefore, any C string with an Str structure contains at least one character before the terminating '\0' . As
a result, after the decrementing in line 18, space is at least 1 , ensuring that at least one character is copied.
String Conversion
If you include <ctype.h> , you can use the two standard functions toupper() and tolower() to convert
individual characters.
But we want to be able to convert entire strings. To do so in a comfortable way and without duplicating
code, you can define a single function for both operations, as shown in Listing 6-20 .
Listing 6-20. str_to_upper_lower()
1. //---------------------------------------------------------- str_to_upper_lower
2. void str_to_upper_lower(Str *str, int (*f)(int)) {
3. #if STR_LOG
4. printf("=== str_to_upper_lower(%p)\n", str);
5. #endif
6. if (str != NULL && str->s != NULL) {
7. char *s = str->s;
8. while (*s != '\0') {
9. *s = (*f)(*s);
10. s++;
11. }
12. }
13. } // str_to_upper_lower
Notice that the third parameter accepts a pointer to a function that accepts an int as single parameter

Some not-so-experienced C programmers might be confused by the statement in line 9, but it will make
sense if you consider that, if f is a function pointer (remember that you passed as argument &toupper or
&tolower ), *f is the function itself. Therefore, you can imagine replacing (*f)() with either toupper() or
tolower() , like this:
*s = toupper(*s);
Then, it becomes obvious that line 9 simply picks the first character of the string and stores it back in the
same position after conversion.
The parentheses around *f are necessary because the parentheses of a function call take precedence
over the dereferencing asterisk (i.e., taking the address of the function). Therefore, if you wrote
*s = *f(*s);
you would effectively be doing the following:
*s = *(f(*s));
That is, you would be attempting to execute f (which is a pointer to a function) as if it were a function
(which it's not). One good place to see the precedence of operators is en.cppreference.com/w/c/language/
operator_precedence . It shows that the parentheses of a function call have precedence 1, while the
dereferencing asterisk (which they call indirection ) has precedence 2. Obviously, you could always use
additional parentheses to set precedences by hand if you are not sure about the default or to remove a
warning issued by an overzealous development environment, but you might like to be a minimalist in this
matter, so that when you see additional parentheses, you know that they need to be there.
The logic of the function is trivial: you go through the string and convert one character at a time until
you hit the terminating NULL .
String Clean Up
What I mean by string clean up is:
Replace all non-printing characters with spaces
Remove all leading spaces
Remove all trailing spaces
Replace all sequences of spaces with a single space
Consider, for example, the string " \t Giulio \t \x15 \r Zambon\t\t \x19\r" . After performing the
four operations listed above, it would look like this: "Giulio Zambon" . Listing 6-21 shows how you do this.
Listing 6-21. str_clean_up()
1. //---------------------------------------------------------------- str_clean_up
2. void str_clean_up(Str *str) {
3. #if STR_LOG
4. printf("=== str_clean_up: %p\n", str);
5. #endif
6. if (str != NULL && str->s != NULL) {
7. char *s0 = str->s;
8. char *s1 = s0;
CHAPTER 6 STRING UTILITIES
160
9. while (*s0 > '\0' && *s0 <= ' ') s0++; // remove leading junk
10. if (*s0 == '\0') {
11. *s1++ = ' ';
12. *s1 = '\0';
13. }
14. else {
15. int space_set = 0;
16. while (*s0 != '\0') {
17. if (*s0 > ' ') {
18. *s1++ = *s0;
19. space_set = 0;
20. }
21. else if (!space_set) {
22. *s1++ = ' ';
23. space_set = 1;
24. }
25. s0++;
26. }
27. if (s1 > str->s) { // we did something
28. *s1-- = '\0';
29. if (*s1 == ' ') *s1 = '\0'; // remove the trailing space

\Giulio

and replaced *s0 and *s1 respectively with s[k0] and s[k1] , but using a pointer is more compact and, IMO,
neater.
Line 9 is where you skip the leading spaces and non-printing characters. Notice that you cannot skip
NULL s because otherwise you would go through the whole computers memory!
The check in line 10 and the setting of s1 in lines 11 and 12 take care of the possibility that the whole input
string might consist of spaces and non-input characters. In that case, you compact it into a single space.
space_set defined in line 15 is a state variable: when set to zero it indicates that the previous character
of s0 you checked was a character you want to keep (i.e., neither a space nor a non-printing character). In
other words, space_set is true when the last character was a space or a non-printing character.
Lines 18 and 19 are executed when the current input character (i.e., the character pointed by s0 ) is to be
kept. Accordingly, you copy it to the position pointed by s1 and increment s1 . But you also reset space_set .
This means that, whenever you encounter several printing characters in sequence, you repeatedly clear
space_set . You might ask: why dont we only set it when necessary? Like in:
if (space_set) space_set = 0;
CHAPTER 6 STRING UTILITIES
161
But, whos to say that a check for non-zero followed by a jump is computationally more economical
than a straight setting to zero? Im not sure. The thing is, I always avoid checks if I can. And, in any case, a
straight assignment is clearer.
If the if statement in line 17 fails, it means that the current character is either a space or a non-printing
character. You only need to do something if it is the first one, because you want to reduce the sequences of
spaces and non-printing characters to single spaces.
If it is the first one (i.e., if space_set is false ), you write a space to the output (line 22) and remember
that you have encountered a space or a non-printing character in input (line 23).
In any case, regardless of what you have encountered in input, you increment the input pointer (line 25)
and move on.
After going through the whole input string, in line 27 you check that you have changed the output
pointer. If that is the case, you know that the output string contains at least one character, and you close it
with a NULL (line 28).
But wait a minute! What if there were trailing spaces and non-printing characters? Well, if there were,
they will have been compacted into a single space. Therefore, you only need to check whether the last
character of the string is a space. If it is, you overwrite it with a NULL (line 29) and you are done.
String Remove
Sometimes it is useful to remove a portion of a string. For this purpose, you can use one of the following
macros:
#define STR_remove(str, from, before) str_remove(str, from, before)
#define STR_remove_from(str, from) str_remove(str, from, STR_len(str))
and replaced *s0 and *s1 respectively with s[k0] and s[k1] , but using a pointer is more compact and, IMO,
neater.
Line 9 is where you skip the leading spaces and non-printing characters. Notice that you cannot skip
NULL s because otherwise you would go through the whole computers memory!
The check in line 10 and the setting of s1 in lines 11 and 12 take care of the possibility that the whole input
string might consist of spaces and non-input characters. In that case, you compact it into a single space.
space_set defined in line 15 is a state variable: when set to zero it indicates that the previous character
of s0 you checked was a character you want to keep (i.e., neither a space nor a non-printing character). In
other words, space_set is true when the last character was a space or a non-printing character.
Lines 18 and 19 are executed when the current input character (i.e., the character pointed by s0 ) is to be
kept. Accordingly, you copy it to the position pointed by s1 and increment s1 . But you also reset space_set .
This means that, whenever you encounter several printing characters in sequence, you repeatedly clear
space_set . You might ask: why dont we only set it when necessary? Like in:
if (space_set) space_set = 0;
CHAPTER 6 STRING UTILITIES
161
But, whos to say that a check for non-zero followed by a jump is computationally more economical
than a straight setting to zero? Im not sure. The thing is, I always avoid checks if I can. And, in any case, a
straight assignment is clearer.
If the if statement in line 17 fails, it means that the current character is either a space or a non-printing
character. You only need to do something if it is the first one, because you want to reduce the sequences of
spaces and non-printing characters to single spaces.
If it is the first one (i.e., if space_set is false ), you write a space to the output (line 22) and remember
that you have encountered a space or a non-printing character in input (line 23).
In any case, regardless of what you have encountered in input, you increment the input pointer (line 25)
and move on.
After going through the whole input string, in line 27 you check that you have changed the output
pointer. If that is the case, you know that the output string contains at least one character, and you close it
with a NULL (line 28).
But wait a minute! What if there were trailing spaces and non-printing characters? Well, if there were,
they will have been compacted into a single space. Therefore, you only need to check whether the last
character of the string is a space. If it is, you overwrite it with a NULL (line 29) and you are done.
String Remove
Sometimes it is useful to remove a portion of a string. For this purpose, you can use one of the following
macros:
#define STR_remove(str, from, before) str_remove(str, from, before)
#define STR_remove_from(str, from) str_remove(str, from, STR_len(str))

and replaced *s0 and *s1 respectively with s[k0] and s[k1] , but using a pointer is more compact and, IMO,
neater.
Line 9 is where you skip the leading spaces and non-printing characters. Notice that you cannot skip
NULL s because otherwise you would go through the whole computers memory!
The check in line 10 and the setting of s1 in lines 11 and 12 take care of the possibility that the whole input
string might consist of spaces and non-input characters. In that case, you compact it into a single space.
space_set defined in line 15 is a state variable: when set to zero it indicates that the previous character
of s0 you checked was a character you want to keep (i.e., neither a space nor a non-printing character). In
other words, space_set is true when the last character was a space or a non-printing character.
Lines 18 and 19 are executed when the current input character (i.e., the character pointed by s0 ) is to be
kept. Accordingly, you copy it to the position pointed by s1 and increment s1 . But you also reset space_set .
This means that, whenever you encounter several printing characters in sequence, you repeatedly clear
space_set . You might ask: why dont we only set it when necessary? Like in:
if (space_set) space_set = 0;
CHAPTER 6 STRING UTILITIES
161
But, whos to say that a check for non-zero followed by a jump is computationally more economical
than a straight setting to zero? Im not sure. The thing is, I always avoid checks if I can. And, in any case, a
straight assignment is clearer.
If the if statement in line 17 fails, it means that the current character is either a space or a non-printing
character. You only need to do something if it is the first one, because you want to reduce the sequences of
spaces and non-printing characters to single spaces.
If it is the first one (i.e., if space_set is false ), you write a space to the output (line 22) and remember
that you have encountered a space or a non-printing character in input (line 23).
In any case, regardless of what you have encountered in input, you increment the input pointer (line 25)
and move on.
After going through the whole input string, in line 27 you check that you have changed the output
pointer. If that is the case, you know that the output string contains at least one character, and you close it
with a NULL (line 28).
But wait a minute! What if there were trailing spaces and non-printing characters? Well, if there were,
they will have been compacted into a single space. Therefore, you only need to check whether the last
character of the string is a space. If it is, you overwrite it with a NULL (line 29) and you are done.
String Remove
Sometimes it is useful to remove a portion of a string. For this purpose, you can use one of the following
macros:
#define STR_remove(str, from, before) str_remove(str, from, before)
#define STR_remove_from(str, from) str_remove(str, from, STR_len(str))

and replaced *s0 and *s1 respectively with s[k0] and s[k1] , but using a pointer is more compact and, IMO,
neater.
Line 9 is where you skip the leading spaces and non-printing characters. Notice that you cannot skip
NULL s because otherwise you would go through the whole computers memory!
The check in line 10 and the setting of s1 in lines 11 and 12 take care of the possibility that the whole input
string might consist of spaces and non-input characters. In that case, you compact it into a single space.
space_set defined in line 15 is a state variable: when set to zero it indicates that the previous character
of s0 you checked was a character you want to keep (i.e., neither a space nor a non-printing character). In
other words, space_set is true when the last character was a space or a non-printing character.
Lines 18 and 19 are executed when the current input character (i.e., the character pointed by s0 ) is to be
kept. Accordingly, you copy it to the position pointed by s1 and increment s1 . But you also reset space_set .
This means that, whenever you encounter several printing characters in sequence, you repeatedly clear
space_set . You might ask: why dont we only set it when necessary? Like in:
if (space_set) space_set = 0;
CHAPTER 6 STRING UTILITIES
161
But, whos to say that a check for non-zero followed by a jump is computationally more economical
than a straight setting to zero? Im not sure. The thing is, I always avoid checks if I can. And, in any case, a
straight assignment is clearer.
If the if statement in line 17 fails, it means that the current character is either a space or a non-printing
character. You only need to do something if it is the first one, because you want to reduce the sequences of
spaces and non-printing characters to single spaces.
If it is the first one (i.e., if space_set is false ), you write a space to the output (line 22) and remember
that you have encountered a space or a non-printing character in input (line 23).
In any case, regardless of what you have encountered in input, you increment the input pointer (line 25)
and move on.
After going through the whole input string, in line 27 you check that you have changed the output
pointer. If that is the case, you know that the output string contains at least one character, and you close it
with a NULL (line 28).
But wait a minute! What if there were trailing spaces and non-printing characters? Well, if there were,
they will have been compacted into a single space. Therefore, you only need to check whether the last
character of the string is a space. If it is, you overwrite it with a NULL (line 29) and you are done.
String Remove
Sometimes it is useful to remove a portion of a string. For this purpose, you can use one of the following
macros:
#define STR_remove(str, from, before) str_remove(str, from, before)
#define STR_remove_from(str, from) str_remove(str, from, STR_len(str))

and replaced *s0 and *s1 respectively with s[k0] and s[k1] , but using a pointer is more compact and, IMO,
neater.
Line 9 is where you skip the leading spaces and non-printing characters. Notice that you cannot skip
NULL s because otherwise you would go through the whole computers memory!
The check in line 10 and the setting of s1 in lines 11 and 12 take care of the possibility that the whole input
string might consist of spaces and non-input characters. In that case, you compact it into a single space.
space_set defined in line 15 is a state variable: when set to zero it indicates that the previous character
of s0 you checked was a character you want to keep (i.e., neither a space nor a non-printing character). In
other words, space_set is true when the last character was a space or a non-printing character.
Lines 18 and 19 are executed when the current input character (i.e., the character pointed by s0 ) is to be
kept. Accordingly, you copy it to the position pointed by s1 and increment s1 . But you also reset space_set .
This means that, whenever you encounter several printing characters in sequence, you repeatedly clear
space_set . You might ask: why dont we only set it when necessary? Like in:
if (space_set) space_set = 0;
CHAPTER 6 STRING UTILITIES
161
But, whos to say that a check for non-zero followed by a jump is computationally more economical
than a straight setting to zero? Im not sure. The thing is, I always avoid checks if I can. And, in any case, a
straight assignment is clearer.
If the if statement in line 17 fails, it means that the current character is either a space or a non-printing
character. You only need to do something if it is the first one, because you want to reduce the sequences of
spaces and non-printing characters to single spaces.
If it is the first one (i.e., if space_set is false ), you write a space to the output (line 22) and remember
that you have encountered a space or a non-printing character in input (line 23).
In any case, regardless of what you have encountered in input, you increment the input pointer (line 25)
and move on.
After going through the whole input string, in line 27 you check that you have changed the output
pointer. If that is the case, you know that the output string contains at least one character, and you close it
with a NULL (line 28).
But wait a minute! What if there were trailing spaces and non-printing characters? Well, if there were,
they will have been compacted into a single space. Therefore, you only need to check whether the last
character of the string is a space. If it is, you overwrite it with a NULL (line 29) and you are done.
String Remove
Sometimes it is useful to remove a portion of a string. For this purpose, you can use one of the following
macros:
#define STR_remove(str, from, before) str_remove(str, from, before)
#define STR_remove_from(str, from) str_remove(str, from, STR_len(str))

and replaced *s0 and *s1 respectively with s[k0] and s[k1] , but using a pointer is more compact and, IMO,
neater.
Line 9 is where you skip the leading spaces and non-printing characters. Notice that you cannot skip
NULL s because otherwise you would go through the whole computers memory!
The check in line 10 and the setting of s1 in lines 11 and 12 take care of the possibility that the whole input
string might consist of spaces and non-input characters. In that case, you compact it into a single space.
space_set defined in line 15 is a state variable: when set to zero it indicates that the previous character
of s0 you checked was a character you want to keep (i.e., neither a space nor a non-printing character). In
other words, space_set is true when the last character was a space or a non-printing character.
Lines 18 and 19 are executed when the current input character (i.e., the character pointed by s0 ) is to be
kept. Accordingly, you copy it to the position pointed by s1 and increment s1 . But you also reset space_set .
This means that, whenever you encounter several printing characters in sequence, you repeatedly clear
space_set . You might ask: why dont we only set it when necessary? Like in:
if (space_set) space_set = 0;
CHAPTER 6 STRING UTILITIES
161
But, whos to say that a check for non-zero followed by a jump is computationally more economical
than a straight setting to zero? Im not sure. The thing is, I always avoid checks if I can. And, in any case, a
straight assignment is clearer.
If the if statement in line 17 fails, it means that the current character is either a space or a non-printing
character. You only need to do something if it is the first one, because you want to reduce the sequences of
spaces and non-printing characters to single spaces.
If it is the first one (i.e., if space_set is false ), you write a space to the output (line 22) and remember
that you have encountered a space or a non-printing character in input (line 23).
In any case, regardless of what you have encountered in input, you increment the input pointer (line 25)
and move on.
After going through the whole input string, in line 27 you check that you have changed the output
pointer. If that is the case, you know that the output string contains at least one character, and you close it
with a NULL (line 28).
But wait a minute! What if there were trailing spaces and non-printing characters? Well, if there were,
they will have been compacted into a single space. Therefore, you only need to check whether the last
character of the string is a space. If it is, you overwrite it with a NULL (line 29) and you are done.
String Remove
Sometimes it is useful to remove a portion of a string. For this purpose, you can use one of the following
macros:
#define STR_remove(str, from, before) str_remove(str, from, before)
#define STR_remove_from(str, from) str_remove(str, from, STR_len(str))

that you have encountered a space or a non-printing character in input (line 23).
In any case, regardless of what you have encountered in input, you increment the input pointer (line 25)
and move on.
After going through the whole input string, in line 27 you check that you have changed the output
pointer. If that is the case, you know that the output string contains at least one character, and you close it
with a NULL (line 28).
But wait a minute! What if there were trailing spaces and non-printing characters? Well, if there were,
they will have been compacted into a single space. Therefore, you only need to check whether the last
character of the string is a space. If it is, you overwrite it with a NULL (line 29) and you are done.
String Remove
Sometimes it is useful to remove a portion of a string. For this purpose, you can use one of the following
macros:
#define STR_remove(str, from, before) str_remove(str, from, before)
#define STR_remove_from(str, from) str_remove(str, from, STR_len(str))

that you have encountered a space or a non-printing character in input (line 23).
In any case, regardless of what you have encountered in input, you increment the input pointer (line 25)
and move on.
After going through the whole input string, in line 27 you check that you have changed the output
pointer. If that is the case, you know that the output string contains at least one character, and you close it
with a NULL (line 28).
But wait a minute! What if there were trailing spaces and non-printing characters? Well, if there were,
they will have been compacted into a single space. Therefore, you only need to check whether the last
character of the string is a space. If it is, you overwrite it with a NULL (line 29) and you are done.
String Remove
Sometimes it is useful to remove a portion of a string. For this purpose, you can use one of the following
macros:
#define STR_remove(str, from, before) str_remove(str, from, before)
#define STR_remove_from(str, from) str_remove(str, from, STR_len(str))
v
v
that you have encountered a space or a non-printing character in input (line 23).
In any case, regardless of what you have encountered in input, you increment the input pointer (line 25)
and move on.
After going through the whole input string, in line 27 you check that you have changed the output
pointer. If that is the case, you know that the output string contains at least one character, and you close it
with a NULL (line 28).
But wait a minute! What if there were trailing spaces and non-printing characters? Well, if there were,
they will have been compacted into a single space. Therefore, you only need to check whether the last
character of the string is a space. If it is, you overwrite it with a NULL (line 29) and you are done.
String Remove
Sometimes it is useful to remove a portion of a string. For this purpose, you can use one of the following
macros:
#define STR_remove(str, from, before) str_remove(str, from, before)
#define STR_remove_from(str, from) str_remove(str, from, STR_len(str))
that you have encountered a space or a non-printing character in input (line 23).
In any case, regardless of what you have encountered in input, you increment the input pointer (line 25)
and move on.
After going through the whole input string, in line 27 you check that you have changed the output
pointer. If that is the case, you know that the output string contains at least one character, and you close it
with a NULL (line 28).
But wait a minute! What if there were trailing spaces and non-printing characters? Well, if there were,
they will have been compacted into a single space. Therefore, you only need to check whether the last
character of the string is a space. If it is, you overwrite it with a NULL (line 29) and you are done.
String Remove
Sometimes it is useful to remove a portion of a string. For this purpose, you can use one of the following
macros:
#define STR_remove(str, from, before) str_remove(str, from, before)
#define STR_remove_from(str, from) str_remove(str, from, STR_len(str))

In any case, regardless of what you have encountered in input, you increment the input pointer (line 25)
and move on.
After going through the whole input string, in line 27 you check that you have changed the output
pointer. If that is the case, you know that the output string contains at least one character, and you close it
with a NULL (line 28).
But wait a minute! What if there were trailing spaces and non-printing characters? Well, if there were,
they will have been compacted into a single space. Therefore, you only need to check whether the last
character of the string is a space. If it is, you overwrite it with a NULL (line 29) and you are done.
String Remove
Sometimes it is useful to remove a portion of a string. For this purpose, you can use one of the following
macros:
#define STR_remove(str, from, before) str_remove(str, from, before)
#define STR_remove_from(str, from) str_remove(str, from, STR_len(str))

In any case, regardless of what you have encountered in input, you increment the input pointer (line 25)
and move on.
After going through the whole input string, in line 27 you check that you have changed the output
pointer. If that is the case, you know that the output string contains at least one character, and you close it
with a NULL (line 28).
But wait a minute! What if there were trailing spaces and non-printing characters? Well, if there were,
they will have been compacted into a single space. Therefore, you only need to check whether the last
character of the string is a space. If it is, you overwrite it with a NULL (line 29) and you are done.
String Remove
Sometimes it is useful to remove a portion of a string. For this purpose, you can use one of the following
macros:
#define STR_remove(str, from, before) str_remove(str, from, before)
#define STR_remove_from(str, from) str_remove(str, from, STR_len(str))
In any case, regardless of what you have encountered in input, you increment the input pointer (line 25)
and move on.
After going through the whole input string, in line 27 you check that you have changed the output
pointer. If that is the case, you know that the output string contains at least one character, and you close it
with a NULL (line 28).
But wait a minute! What if there were trailing spaces and non-printing characters? Well, if there were,
they will have been compacted into a single space. Therefore, you only need to check whether the last
character of the string is a space. If it is, you overwrite it with a NULL (line 29) and you are done.
String Remove
Sometimes it is useful to remove a portion of a string. For this purpose, you can use one of the following
macros:
#define STR_remove(str, from, before) str_remove(str, from, before)
#define STR_remove_from(str, from) str_remove(str, from, STR_len(str))
In any case, regardless of what you have encountered in input, you increment the input pointer (line 25)
and move on.
After going through the whole input string, in line 27 you check that you have changed the output
pointer. If that is the case, you know that the output string contains at least one character, and you close it
with a NULL (line 28).
But wait a minute! What if there were trailing spaces and non-printing characters? Well, if there were,
they will have been compacted into a single space. Therefore, you only need to check whether the last
character of the string is a space. If it is, you overwrite it with a NULL (line 29) and you are done.
String Remove
Sometimes it is useful to remove a portion of a string. For this purpose, you can use one of the following
macros:
#define STR_remove(str, from, before) str_remove(str, from, before)
#define STR_remove_from(str, from) str_remove(str, from, STR_len(str))

In any case, regardless of what you have encountered in input, you increment the input pointer (line 25)
and move on.
After going through the whole input string, in line 27 you check that you have changed the output
pointer. If that is the case, you know that the output string contains at least one character, and you close it
with a NULL (line 28).
But wait a minute! What if there were trailing spaces and non-printing characters? Well, if there were,
they will have been compacted into a single space. Therefore, you only need to check whether the last
character of the string is a space. If it is, you overwrite it with a NULL (line 29) and you are done.
String Remove
Sometimes it is useful to remove a portion of a string. For this purpose, you can use one of the following
macros:
#define STR_remove(str, from, before) str_remove(str, from, before)
#define STR_remove_from(str, from) str_remove(str, from, STR_len(str))
v
In any case, regardless of what you have encountered in input, you increment the input pointer (line 25)
and move on.
After going through the whole input string, in line 27 you check that you have changed the output
pointer. If that is the case, you know that the output string contains at least one character, and you close it
with a NULL (line 28).
But wait a minute! What if there were trailing spaces and non-printing characters? Well, if there were,
they will have been compacted into a single space. Therefore, you only need to check whether the last
character of the string is a space. If it is, you overwrite it with a NULL (line 29) and you are done.
String Remove
Sometimes it is useful to remove a portion of a string. For this purpose, you can use one of the following
macros:
#define STR_remove(str, from, before) str_remove(str, from, before)
#define STR_remove_from(str, from) str_remove(str, from, STR_len(str))
In any case, regardless of what you have encountered in input, you increment the input pointer (line 25)
and move on.
After going through the whole input string, in line 27 you check that you have changed the output
pointer. If that is the case, you know that the output string contains at least one character, and you close it
with a NULL (line 28).
But wait a minute! What if there were trailing spaces and non-printing characters? Well, if there were,
they will have been compacted into a single space. Therefore, you only need to check whether the last
character of the string is a space. If it is, you overwrite it with a NULL (line 29) and you are done.
String Remove
Sometimes it is useful to remove a portion of a string. For this purpose, you can use one of the following
macros:
#define STR_remove(str, from, before) str_remove(str, from, before)
#define STR_remove_from(str, from) str_remove(str, from, STR_len(str))
In any case, regardless of what you have encountered in input, you increment the input pointer (line 25)
and move on.
After going through the whole input string, in line 27 you check that you have changed the output
pointer. If that is the case, you know that the output string contains at least one character, and you close it
with a NULL (line 28).
But wait a minute! What if there were trailing spaces and non-printing characters? Well, if there were,
they will have been compacted into a single space. Therefore, you only need to check whether the last
character of the string is a space. If it is, you overwrite it with a NULL (line 29) and you are done.
String Remove
Sometimes it is useful to remove a portion of a string. For this purpose, you can use one of the following
macros:
#define STR_remove(str, from, before) str_remove(str, from, before)
#define STR_remove_from(str, from) str_remove(str, from, STR_len(str))

You might also like