找出错误或错误
你能找到以下代码的错误吗?
int main(){ char *p="hai friends",*p1; p1=p; while(*p!='\0') ++*p++; printf("%s %s",p,p1); }
我预计它将打印空格后跟一个字符串!
这是一种使用++*p++
:
#include #include int main(int argc, char* argv[]) { char *p = "My test string", p1[15]; strncpy(p1, p, 14); p1[14] = 0; p = p1; while (*p != 0) { printf("%c", ++*p++); } }
请注意, p1
是在堆栈上分配的内存数组(通常),而p
是(通常)指向只读内存的指针,上面的代码移动到指向p1
而不是(通常)只读位置驻留。 某些操作系统和/或编译器将表现出其他行为,但这是现代操作系统内置的一种保护机制,可以防止某些类别的病毒。
表达式++*p++
; 相当于;
++*p; p++;
++*p;
手段
*p = *p + 1;
因为postfix ++
优先级高于取消引用运算符*
,所以它适用于*p
。
并且p
指向一个常量字符串文字。 在上面的操作中,您试图“在只读内存上写入” – 这是非法的 – 因此错误。
建议:
首先 – 声明一个可以修改的数组,不能更改字符串文字。
声明(阅读评论):
char string_array[] ="hai friends"; // notice `[]` in this declaration // that makes `string_array` array // to keep save original string do: char p1[20]; // sufficient length // notice here `p1` is not pointer. strcpy(p1, string_array) ; char *p = string_array;
现在您可以修改指针p
和string_array[]
数组内容。
虽然Grijesh Chauhan的回答是正确的说法:
++*p++;
和
++*p; p++;
具有相同的效果,编译器不会将第一个表达式解释为像第二个表达式一样。 第一个表达式的括号版本是:
++(*(p++));
这意味着逻辑上 – 尽管编译器可以重新排序细节,只要结果是相同的 – p
的后增量发生在结果被取消引用之前,并且预增量对原始值指向的数据进行操作。 p
。 让我们一步一步地完成:
-
p++
– 返回p++
的原始值并将p
递增以指向下一个字符。 -
*(p++)
– 取消引用p
的原始值。 -
++(*(p++)
– 递增++(*(p++)
的原始值指向的对象,并返回该对象的递增值。
因此,给定此代码(避免修改字符串文字 – 这是未定义的行为):
#include int main(void) { char array[] = "ayqm"; char *p = array; char c; c = ++*p++; printf("%c\n", c); printf("%s\n", array); // Print the string c = ++*p++; // Repeat the process printf("%c\n", c); printf("%s\n", array); return 0; }
输出是:
b byqm z bzqm
这个答案中的任何内容都不应被解释为鼓励使用像++*p++
那样复杂的表达式。 理解或维护C并不容易,因此它不好C.但是,它是合法的C.如果变量p
指向初始化的可修改内存,则++*p++
的行为是完全定义的。