我有一个代码块:
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++); 你能告诉我这个公式中的操作顺序吗?
我有一个代码块:
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++); 你能告诉我这个公式中的操作顺序吗?
这是经典的 C 代码,试图通过将所有内容放在一行中来看起来非常聪明。
while (*p2++ = *p1++);
相当于
strcpy(p2, p1);
p1 += strlen(p1) + 1;
p2 += strlen(p2) + 1;
换句话说,它复制了一个以空字符结尾的字符串,p1
最终指向源字符串的结尾并p2
指向目标字符串的结尾。
这是一个字符串副本,但您正在丢失原始指针值。您应该保存原始指针值。
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
to的保存c
可以在保存后的任何时间发生q1
。c
to的分配可以在保存*q2
后的任何时间发生。c
在我的信封背面,这至少有 40 种不同的解释。
循环正在评估while
表达式:*p2++ = *p1++
。while
循环表达式
*p2 = *p1
:使用*p1
. *p2
但是,即使表达式的计算结果为false
or ,此值仍会分配给(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
以确保分配成功。