你能发现下面的代码有什么问题吗?
int main(){
char *p="hai friends",*p1;
p1=p;
while(*p!='\0') ++*p++;
printf("%s %s",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 <stdio.h>
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++
是完全定义的。
这是一种使用方法++*p++
:
#include <stdio.h>
#include <string.h>
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
而不是(通常)字符串所在的只读位置。一些操作系统和/或编译器会表现出其他行为,但这是现代操作系统内置的保护机制之一,用于防止某些类别的病毒。