-3

你能发现下面的代码有什么问题吗?

int main(){
    char *p="hai friends",*p1;
    p1=p;
    while(*p!='\0') ++*p++;
    printf("%s %s",p,p1);
}

我希望它会打印空格,后跟一个字符串!

4

3 回答 3

9

表达式++*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;

现在您可以修改指针pstring_array[]数组内容。

于 2013-07-23T19:05:15.097 回答
4

尽管Grijesh Chauhan的回答是正确的:

++*p++;

++*p;
p++;

具有相同的效果,编译器不会将第一个表达式解释为像第二个那样编写。第一个表达式的括号版本是:

++(*(p++));

这意味着在逻辑上——尽管编译器可以对细节重新排序,只要结果相同——后增量p发生在结果被取消引用之前,并且前增量对原始值指向的数据进行操作p。让我们一步一步来:

  1. p++— 返回 的原始值p并递增p以指向下一个字符。
  2. *(p++)— 取消引用 的原始值p
  3. ++(*(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++是完全定义的。

于 2013-08-31T17:51:28.947 回答
0

这是一种使用方法++*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而不是(通常)字符串所在的只读位置。一些操作系统和/或编译器会表现出其他行为,但这是现代操作系统内置的保护机制之一,用于防止某些类别的病毒。

于 2013-07-23T19:22:45.793 回答