Presumably your first example is supposed to call foo1 and your second is supposed to call foo2 (with a properly defined s).
The postfix increment operator has higher precedence than the dereferencing operator. So foo1 actually says the following and therefore does absolutely nothing. If you are compiling with full warnings you should get a warning.
Code:
void foo1(char **p) { *(p++); } // This is how *p++ is interpreted by the precedence rules
To make foo1 actually do something (acting like foo2) :
Code:
void foo1(char **p) { (*p)++; }
Or more intelligently, IMO :
Code:
void foo1(char **p) { ++*p; }
Your explanation of why foo2 (and the new-and-improved foo1) do what they do is correct.