最近我看到一个使用这样代码的项目:
while ((*dest++ = *src++) != '\0')
...
我想知道*dest++ = *src++
的行为是否定义明确?它总是表现为:
while((*dest = *src) != '\0') {
++dest;
++src;
...
}
或者此代码是否属于a[i] = i++;
?
答案 0 :(得分:2)
有问题的代码与K& R的代码几乎完全相同,其行为也很明确。
没有未定义行为的原因是该行上的四次访问是在三个不同的内存位置完成的:
dest++
增加dest
指针,src++
增加src
指针,*dest =
分配dest
,*src
读取src
指向的内容。如果代码在没有序列点的情况下多次尝试访问同一位置,则该代码将变为非法。 x += x++
。这是未定义的行为,因为++
和+=
都在修改x
的相同位置。
答案 1 :(得分:0)
x++ = y++
是非法的,因为赋值的左侧必须是存储引用,但x ++是值,而不是左值。
* dest ++ = * src ++是有效的,因为在这种情况下,dest是一个指针(++后递增),但是赋值是指向的是什么,因此是一个有效的地址,可以分配给值。
如果你看一下strcpy的实现,它会使用这个结构:
char *strcpy(char *d, const char *s)
{
char *saved = d;
while (*s)
{
*d++ = *s++;
}
*d = 0;
return saved;
}
答案 2 :(得分:0)
是。由Brian W. Kernighan和Dennis M. Ritchie撰写的K& R对此进行了解释。
第二版,第104页:
相比之下,这是一个带指针的strcpy版本:
/* strcpy: copy t to s; pointer version 1 */ void strcpy(char *s, char *t) { while((*s = *t) != '\0') { s ++; t ++; } }
因为参数是按值传递的,所以strcpy可以使用参数s 并且以任何方式令人高兴。在这里他们很方便地初始化 指针,一次沿着数组行进一个字符, 直到'\ 0'终止t已被复制到s。
在实践中,strcpy不会像我们上面所示那样被写入。 有经验的C程序员更喜欢
/* strcpy: copy t to s; pointer version 2 */ void strcpy(char *s, char *t) { while((*s++ = *t++) != '\0') ; }
这会将s和t的增量移动到循环的测试部分。 * t ++的值是t之前指向的字符 增加;在此之后,postfix ++不会改变 字符已被取出。以同样的方式,存储角色 在s增加之前进入旧s位置。这个角色是 还有与'\ 0'比较的值来控制循环。该 净效应是将字符从t复制到s,最多为和 包括终止'\ 0'。
作为最后的缩写,请注意与'\ 0'的比较 多余的,因为这个问题仅仅是表达式 零。所以函数可能写成
/* strcpy: cope t to s; pointer version 3 */ void strcpy(char *s, char *t) { while(*s++, *t++); }
答案 3 :(得分:0)
构造((* dst ++ = * src ++)!= 0)或' \ 0'与0相同 它既定义明确,也是一种常见的习惯用法,特别是在早期的C代码中。它将指针类型的一个值从src复制到dest,并定位src和dst指针,将下一个相邻的src值复制到下一个相邻的dst位置。
这用于strcpy之类的实现。
答案 4 :(得分:0)
是的,似乎很明确。我刚才拿了C,但我会说指针* dest和* src指向dest和src的内存地址。如果您尝试使用++运算符递增dest和src变量的值,那就没问题。我希望这是有道理的。