Yes. K&R by Brian W. Kernighan and Dennis M. Ritchie gives an explanation of this.
Second Edition, Page 104:
For contrast, here is a version of strcpy with pointers:
/* strcpy: copy t to s; pointer version 1 */
void strcpy(char *s, char *t)
{
while((*s = *t) != '\0')
{
s ++;
t ++;
}
}
Because arguments are passed by value, strcpy can use the parameters s
and t in any way it pleases. Here they are conveniently initialized
pointers, which are marched along the arrays a character at a time,
until the '\0' that terminates t has been copied to s.
In practice, strcpy would not be written as we showed it above.
Experienced C programmers would prefer
/* strcpy: copy t to s; pointer version 2 */
void strcpy(char *s, char *t)
{
while((*s++ = *t++) != '\0')
;
}
This moves the increment of s and t into the test part of the loop.
The value of *t++ is the character that t pointed to before t was
incremented; the postfix ++ doesn't change t until after this
character has been fetched. In the same way, the character is stored
into the old s position before s is incremented. This character is
also the value that is compared against '\0' to control the loop. The
net effect is that characters are copied from t to s, up to and
including the terminating '\0'.
As the final abbreviation, observe that a comparison against '\0' is
redundant, since the question is merely whether the expression is
zero. So the function would likely be written as
/* strcpy: cope t to s; pointer version 3 */
void strcpy(char *s, char *t)
{
while(*s++, *t++);
}