Supponiamo di chiamare ultimaLettera sulla stringa "parola".
codice:
s --+
V
+---+---+---+---+---+---+----+ · · ·
| p | a | r | o | l | a | \0 | ·
+---+---+---+---+---+---+----+ · · ·
finché s punta ad una lettera valida non succede nulla di che.
Ora esaminiamo il caso in cui s sia arrivato al \0:
codice:
s ---------------------------+
V
+---+---+---+---+---+---+----+ · · · · ·
| p | a | r | o | l | a | \0 | · ·
+---+---+---+---+---+---+----+ · · · · ·
qui viene valutata l'espressione
che restituisce 0 (facendo terminare il while) ma incrementa s; per cui, all'uscita del while la situazione è la seguente:
codice:
s -------------------------------+
V
+---+---+---+---+---+---+----+ · · · · ·
| p | a | r | o | l | a | \0 | · ·
+---+---+---+---+---+---+----+ · · · · ·
ovvero, s punta alla "posizione fantasma" immediatamente dopo il carattere di fine stringa†.
A questo punto, per tornare all'ultimo carattere "vero" bisogna tornare indietro di due posizioni
codice:
s -------------------------------+
|
s-2 --------------------+ |
V V
+---+---+---+---+---+---+----+ · · · · ·
| p | a | r | o | l | a | \0 | · ·
+---+---+---+---+---+---+----+ · · · · ·
da cui:
(per chiarezza: s[-2] è uguale per definizione a *(s-2))
Nota comunque che questo codice non considera il caso speciale di una stringa vuota (ovvero, contenente solo il terminatore); in tal caso, si restituirebbe un puntatore non valido; per ovviare a questo problema, si può aggiungere un caso speciale all'inizio:
codice:
char ultimaLettera(stringa s)
{
if(!*s)
return 0;
while(*s++);
return s[-2];
}
-----
† nota che questo è ammesso dallo standard - si garantisce che l'aritmetica dei puntatori funzioni correttamente fino ad un elemento dopo l'ultimo, in modo da poter esprimere i range come intervalli semiaperti [inizio, fine).