What does while (*p2++ = *p1++); mean? [duplicate]

2020-07-16 02:32发布

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?

标签: c
3条回答
家丑人穷心不美
2楼-- · 2020-07-16 02:57

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.

查看更多
劳资没心,怎么记你
3楼-- · 2020-07-16 03:00

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.

查看更多
贪生不怕死
4楼-- · 2020-07-16 03:03

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.

查看更多
登录 后发表回答