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?
It's classic C code trying to look extremely clever by putting everything in one line.
while (*p2++ = *p1++);
is equivalent to
strcpy(p2, p1);
p1 += strlen(p1) + 1;
p2 += strlen(p2) + 1;
In other words, it copies a null-terminated string, with p1
ending up pointing to the end of the source string and p2
pointing to the end of the destination string.
This is a string copy, but you are losing the original pointer value. You should save the original pointer value.
int main ()
{
char *p1 = "Hello";
char *p2 = malloc(20);
char *p3 = p2;
memset (p2, 0, 20);
while (*p2++ = *p1++);
printf ("%s\n", p3);
}
The actual semantic explanation of the while loop would be something like:
for (;;) {
char *q2 = p2; // original p2 in q2
char *q1 = p1; // original p1 in q1
char c = *q1; // original *p1 in c
p2 += 1; // complete post increment of p2
p1 += 1; // complete post increment of p1
*q2 = c; // copy character *q1 into *q2
if (c) continue; // continue if c is not 0
break; // otherwise loop ends
}
The order that q1
and q2
are saved, and the order that p2
and p1
are incremented may be interchanged. The save of *q1
to c
can occur any time after q1
is saved. The assignment of c
to *q2
can occur any time after c
is saved. On the back of my envelop, this works out to at least 40 different interpretations.
The while
loop is evaluating the expression: *p2++ = *p1++
. The while
loop expression:*p2 = *p1
is evaluated using the result of *p1
. However, this value is still assigned to *p2
even if the expression evaluates as false
or (0)
. Rewriting this:
char c;
do
{
c = *p1; /* read the src byte */
*p2 = c; /* write to dst byte */
p2++, p1++; /* increment src, dst pointers */
}
while (c != 0);
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, and p2
has enough storage for the C string. That is, malloc
should allocate at least strlen(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 of p2
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:
char *p1 = "Hello";
char *p2, *tmp;
p2 = (char*)malloc (20);
memset (p2, 0, 20);
tmp = p2;
while (*tmp++ = *p1++);
printf ("%s\n", p2);
Most operating systems will release the memory at p2
on exit from main
, but it is good practice to unwind the resources with a corresponding call to:
free(p2);
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With