C function to capitalize first word in a sentence, handles arbitrary spaces The code below capitalized the first letter of every word in a sentence. It handles an arbitrary number of spaces in any part of string. It works. Can it be optimized further?

void capitalize_string(char *s) {
  while(*s) {
    while (*s &amp;&amp; *s == ' ')
      s++;
    *s = toupper(*s);
    s++;
    while (*s &amp;&amp; *s != ' ')
      s++;
  }
}
Declare the toupper function
The easiest way to provide a prototype is
#include &lt;ctype.h&gt;

Consider matching all whitespace
At present, we don't capitalize a word at the beginning of a line.  We could deal with this by using isspace() instead of testing for equality with ' '.  Also, we might want to consider a word to start when a letter immediately follows punctuation (such as &quot;, / or -).
Bug: if the string ends with a space
Consider the string &quot;  &quot; and walk through.
We loop while (*s &amp;&amp; *s == ' ') until s points at the terminating NUL character.  Now we upcase that NUL (which is harmless), and increment s again.  That's not good.
We need
 if (!*s) { break; }

before line 6.
An alternative approach
Instead of changing between two different loops for whitespace and non-whitespace runs, we can write a single loop if we use a variable to remember what we've most recently seen; I'll call it prev.  Start off with it set to a space, so that we'll capitalise the first letter of the string.  The code then looks like this:
#include &lt;ctype.h&gt;

void capitalize_string(char *s)
{
    for (int prev = ' ';  *s;  ++s) {
        int current = (unsigned char)*s;
        if (!isalnum(prev) &amp;&amp; isalpha(current)) {
            *s = (char)toupper(current);
        }
        prev = current;
    }
}

Note that the &lt;ctype.h&gt; functions all accept (and return) an int that represents an unsigned char version of a character - on platforms where plain char is signed, passing one directly can be undefined behaviour.
Here's a short test program so we can give command-line arguments to try out:
#include &lt;stdio.h&gt;
int main(int argc, char **argv)
{
    for (int i = 1;  i &lt; argc;  ++i) {
        capitalize_string(argv[i]);
        printf(&quot;%s\n&quot;, argv[i]);
    }
}

A more sophisticated test allows us to check a suite of examples every time we make a change to the code, and allows us to be explicit about our expectations:
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
int check(const char *input, const char *expected)
{
    char *s = malloc(strlen(input)+1);
    if (!s) {
        perror(&quot;malloc&quot;);
        return 1;
    }
    strcpy(s, input);

    int err_count = 0;
    capitalize_string(s);
    if (strcmp(s, expected)) {
        fprintf(stderr, &quot;*** Input \&quot;%s\&quot;; expected \&quot;%s\&quot;; got \&quot;%s\&quot;\n&quot;,
                input, expected, s);
        ++err_count;
    }

    free(s);
    return err_count;
}

int main()
{
    return check(&quot;&quot;, &quot;&quot;)
        +  check(&quot;123&quot;, &quot;123&quot;)
        +  check(&quot;ab&quot;, &quot;Ab&quot;)
        +  check(&quot;AB&quot;, &quot;AB&quot;)
        +  check(&quot;ab cd&quot;, &quot;Ab Cd&quot;)
        +  /* add more tests here */
        +  check(&quot;harley-davidson&quot;, &quot;Harley-Davidson&quot;)
        ;
}