Pig Latin translator in C
Inadvertent case dependency?

Should not the below code also work with 'Q', 'U'?

if (*s == 'q' &amp;&amp; *(s+1) == 'u')


char functions (advanced issue)`

The Std C library functions treat  char * data as if it was accessed by unsigned char *.

This is important in select cases.

tolower(int ch), is...() are well defined for values in the unsigned char range and EOF, else UB.  When *s &lt; 0, tolower(*s) is a problem.  Casting to (unsigned char) fixes that.

isvowel(const char *s) {
  // switch (tolower(*s)) {
  switch (tolower((unsigned char) *s)) {


With some extended ASCII encoding this is useful, yet with UTF8, the issue moot as tolower() is wholly inadequate.



Deeper pedantic detail

(unsigned char) *s is the wrong solution with non-2's complement and signed char (not seen these days) as code should access the data an unsigned char.  

isvowel(const char *s) {
  const char *us = (const char *) s;
  switch (tolower(*us)) {


With 2's complement the result is the same with either approach.  IAC, I doubt much C code these days would survive a new non-2's complement integer encoding so no real reason to worry about this deep detail.

Formatting

Code lacks {} in simple blocks.  I find the later style easier to review and maintain.  As with such style issues, code to your group's coding standard.

} else {
    while (argc-- &gt; 0)
        piglatin(*argv++);
}


vs.

} else {
    while (argc-- &gt; 0) {
        piglatin(*argv++); 
    }
}


Consider local variables, initialization and code reduction

//bool upper;
//...
//    upper = false;
//    if (isupper(*s))
//        upper = true;
      bool upper = isupper(*s);