How does this loop end?

I found this on one of Nick Gammon's pages. I get all the SPI stuff and I get how this iterates through the string by moving the pointer and setting c to the character being pointed to each time. But how does this ever end?

for (const char * p = "Fab" ; c = *p; p++)
    SPI.transfer (c);

The loop terminates when the condition expression - the second thing in the for() statement - evaluates as 0, or false. In this case, that expression is an assignment, which returns the value that's assigned to the left-hand side. The string that pointer p points to has four elements: three printable characters, followed by a terminating null, or 0. When the pointer is incremented to point to the fourth character, it assigns the value of 0 to character variable c. The assignment evaluates as 0, or false, and the loop terminates.

You can verify that the loop does indeed terminate, without building an SPI gizmo, by substituting a Serial.print() for the SPI.transfer in Nick's code, and then printing something afterward to prove that the processor hasn't hung. To see the "stop on null" characteristic in action, you can insert a null in the string, like this:

const char * p = "Fa\0b" ;

and the code will print

Fa

In a for loop is almost exactly equivalent to a while loop thus:

for (<a> ; <b> ; <c>)
  <body>

is treated like

{
  <a>
  while (<b>)
  {
    <body> ;
    <c>
  }
}

So that example loop becomes:

{
  const char * p = "Fab" ;
  while (c = *p)
  { 
    SPI.transfer (c);
    p++
  }
}

The use of “almost exactly” above is because there is a difference, I think,
such as the continue statement doesn’t skip the clause.

So that example loop becomes:

except that the p++ line has a ; at the end.

Oh yes, forgot that little weirdness of C. At least you don't
need a comma at the end of every argument and value list!!

while c=*p is not a conditional, the loop will evaluate it and terminate whenever the value of p (*p) is equal to zero, since zero is considered false and non-zero true.

Aha, I get it. I didn't think about the terminating null because I didn't see it. I forgot it was there when you initialize a constant string.

This makes perfect sense now, thanks!