我有一个代码块:
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 ++); 你能让我知道这个公式中的操作顺序吗?
答案 0 :(得分:18)
这是经典的C代码,试图通过将所有内容放在一行来看起来非常聪明。
while (*p2++ = *p1++);
相当于
strcpy(p2, p1);
p1 += strlen(p1) + 1;
p2 += strlen(p2) + 1;
换句话说,它复制一个以空字符结尾的字符串,其中p1
最后指向源字符串的末尾,p2
指向目标字符串的末尾。
答案 1 :(得分: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
}
保存q1
和q2
的顺序以及p2
和p1
递增的顺序可以互换。保存*q1
后,c
保存到q1
可能会随时发生。 c
*q2
的分配可以在c
保存后随时进行。在我的信封背面,这至少有40种不同的解释。
答案 2 :(得分:1)
while
循环正在评估表达式:*p2++ = *p1++
。 while
循环表达式:
使用*p2 = *p1
的结果评估*p1
。但是,即使表达式的计算结果为*p2
或false
,此值仍会分配给(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-last-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
的返回值,以确保分配成功。