5

我有一个代码块:

int main ()
{
    char *p1 = "Hello";
    char *p2;
    p2 = (char*)malloc (20);
    memset (p2, 0, 20);
    while (*p2++ = *p1++);
    printf ("%s\n", p2);
}

但是我无法解释该行的工作 while (*p2++ = *p1++); 你能告诉我这个公式中的操作顺序吗?

4

3 回答 3

18

这是经典的 C 代码,试图通过将所有内容放在一行中来看起来非常聪明。

while (*p2++ = *p1++);相当于

strcpy(p2, p1);
p1 += strlen(p1) + 1;
p2 += strlen(p2) + 1;

换句话说,它复制了一个以空字符结尾的字符串,p1最终指向源字符串的结尾并p2指向目标字符串的结尾。

于 2013-05-16T07:08:47.827 回答
9

这是一个字符串副本,但您正在丢失原始指针值。您应该保存原始指针值。

int main ()
{
    char *p1 = "Hello";
    char *p2 = malloc(20);
    char *p3 = p2;
    memset (p2, 0, 20);
    while (*p2++ = *p1++);
    printf ("%s\n", p3);
}

while 循环的实际语义解释类似于:

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
}

q1q2被保存的顺序和p2p1递增的顺序可以互换。*q1to的保存c可以在保存后的任何时间发生q1cto的分配可以在保存*q2后的任何时间发生。c在我的信封背面,这至少有 40 种不同的解释。

于 2013-05-16T07:11:34.177 回答
1

循环正在评估while表达式:*p2++ = *p1++while循环表达式
*p2 = *p1:使用*p1. *p2但是,即使表达式的计算结果为falseor ,此值仍会分配给(0)。重写这个:

char c;

do
{
    c = *p1; /* read the src byte */
    *p2 = c; /* write to dst byte */

    p2++, p1++; /* increment src, dst pointers */
}
while (c != 0);

您会注意到至少会发生一次读/写。没关系,只要 C 字符串p1是 nul 终止的,并且p2有足够的存储空间来存储 C 字符串。也就是说,malloc应该至少分配strlen(p1) + 1字节。在提供的此代码中,这是真的。

正如其他人指出的那样,最终迭代将离开p1地址one-past-the-end,这仍然是一个有效的指针,但在取消引用时具有未定义的结果。的地址p2既是一个有效的指针,也是一个有效的取消引用,因为您分配了 20 个字节。但是,p2不再指向 C 字符串副本。你想要的是相当于:

char *p1 = "Hello";
char *p2, *tmp;

p2 = (char*)malloc (20);
memset (p2, 0, 20);

tmp = p2;
while (*tmp++ = *p1++);

printf ("%s\n", p2);

大多数操作系统会p2在退出时释放内存main,但最好通过相应的调用来展开资源:

free(p2);

在最后。在良好实践的主题上,您还应该检查返回值malloc以确保分配成功。

于 2013-05-16T08:12:55.373 回答