Professional Documents
Culture Documents
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