I have a code block:
int main ()
{
char *p1 = "Hello";
char *p2;
p2 = (char*)malloc (20);
memset (p2, 0, 20);
while (*p2++ = *p1++);
printf ("%s\n", p2);
}
But I can not explain the working of the line while (*p2++ = *p1++); Could you let me know the order of operation in this formula?
This is a string copy, but you are losing the original pointer value. You should save the original pointer value.
The actual semantic explanation of the while loop would be something like:
The order that
q1
andq2
are saved, and the order thatp2
andp1
are incremented may be interchanged. The save of*q1
toc
can occur any time afterq1
is saved. The assignment ofc
to*q2
can occur any time afterc
is saved. On the back of my envelop, this works out to at least 40 different interpretations.It's classic C code trying to look extremely clever by putting everything in one line.
while (*p2++ = *p1++);
is equivalent toIn other words, it copies a null-terminated string, with
p1
ending up pointing to the end of the source string andp2
pointing to the end of the destination string.The
while
loop is evaluating the expression:*p2++ = *p1++
. Thewhile
loop expression:*p2 = *p1
is evaluated using the result of*p1
. However, this value is still assigned to*p2
even if the expression evaluates asfalse
or(0)
. Rewriting this:You will notice that a read / write will occur at least once. That's OK, as long as the C string
p1
is nul-terminated, andp2
has enough storage for the C string. That is,malloc
should allocate at leaststrlen(p1) + 1
bytes. In this code provided, this is true.As others have pointed out, the final iteration will leave
p1
at an address one-past-the-end, which is still a valid pointer, but has undefined results when dereferenced. The address ofp2
is both a valid pointer, and a valid dereference, since you're allocating 20 bytes. However,p2
does not point to the C string copy any longer. What you want is an equivalent to:Most operating systems will release the memory at
p2
on exit frommain
, but it is good practice to unwind the resources with a corresponding call to:at the end. While on the subject of good practice, you should also check the return value of
malloc
to ensure that the allocation succeeded.