猿问
下载APP

指针表达式:* ptr ++,* ++ ptr和++ * ptr

最近我遇到了这个我自己无法理解的问题。


这三个表达式真正意味着什么?


*ptr++

*++ptr

++*ptr

我试过里奇。但不幸的是,他无法按照他讲述的这三项行动。


我知道它们都是为了递增指针/指向的值而执行的。我还可以猜测可能有很多关于优先级和评估顺序的事情。就像一个指针首先递增指针然后取出指针的内容,一个简单地取出内容然后递增指针等等。正如你所看到的,我对他们的实际操作我没有清楚的理解,我想尽快明确。但是当我有机会将它们应用到程序中时,我真的迷失了。例如:


int main()

{

    const char *p = "Hello";

    while(*p++)

         printf("%c",*p);

    return 0;

}

给我这个输出:


ello

但我的期望是它会印刷Hello。最后一个请求 - 请给出一些示例,说明每个表达式在给定的代码段中的工作原理。因为大多数时候只有一段理论飞过我的脑海。


米脂
浏览 56回答 3
3回答

白板的微信

这是一个详细的解释,我希望对此有所帮助。让我们从您的程序开始,因为它是最简单的解释。int main(){    const char *p = "Hello";    while(*p++)        printf("%c",*p);    return 0;}第一个声明:const char* p = "Hello";声明p为指向char。当我们说“指向一个char”时,这是什么意思?这意味着值p是a的地址char;  p告诉我们在记忆中哪里留有一些空间来容纳一个char。该语句还初始化p为指向字符串文字中的第一个字符"Hello"。为了这个练习,重要的是理解p为不指向整个字符串,而只指向第一个字符'H'。毕竟,p是一个指针char,而不是整个字符串。值p是'H'in 的地址"Hello"。然后你设置一个循环:while (*p++)循环条件*p++是什么意思?这里有三件事令人费解(至少在熟悉之前):两个运算符的优先级,后缀++和间接*后缀增量表达式的值后缀增量表达式的副作用1.优先权。快速浏览一下运算符的优先级表会告诉您postfix增量的优先级(16)高于dereference / indirection(15)。这意味着复杂表达式*p++将被分组为:*(p++)。也就是说,该*零件将应用于零件的值p++。所以让我们p++先来看看这个部分。2.后缀表达式值。值p++是p 增量前的值。如果你有:int i = 7;printf ("%d\n", i++);printf ("%d\n", i);输出将是:78因为在增量之前i++评估i。同样地p++,要评估当前的价值p。众所周知,当前的值p是地址'H'。所以现在已经评估了p++部分内容*p++; 这是当前的价值p。然后*部分发生了。*(current value of p)意思是:访问所持地址的值p。我们知道那个地址的价值是'H'。所以表达式的*p++计算结果为'H'。现在等一下,你说。如果*p++评估为'H',为什么不在'H'上面的代码中打印?这就是副作用的来源。3.后缀表达式副作用。后缀++具有当前操作数的值,但它具有递增该操作数的副作用。咦?int再看看那段代码:int i = 7;printf ("%d\n", i++);printf ("%d\n", i);如前所述,输出将是:78当i++在第一评估printf()中,评估为7.但C标准保证在之前所述第二某点printf()处开始执行,在副作用的的++操作员将已经发生。也就是说,在第二次printf()发生之前,i由于++第一次运算符的结果将增加printf()。顺便说一下,这是标准给出的关于副作用时间的少数保证之一。然后,在您的代码中,当计算表达式时*p++,它的计算结果为'H'。但到了这个时候:printf ("%c", *p)发生了令人讨厌的副作用。p已增加。哇!它不再指向'H',而是指过去的一个角色'H':'e'换句话说。这解释了你的cockneyfied输出:ello因此,在其他答案中的有用(和准确)建议的合唱:打印收到的发音"Hello"而不是它的cockney对应,你需要类似的东西while (*p)    printf ("%c", *p++);这么多。剩下的呢?你问这些意义:*ptr++*++ptr++*ptr我们刚才谈到了第一个,所以让我们来看看第二个:*++ptr。我们在前面的解释中看到,后缀增量p++具有一定的优先级,值和副作用。前缀增量++p具有与其后缀对应物相同的副作用:它将其操作数增加1.但是,它具有不同的优先级和不同的值。前缀增量的优先级低于后缀; 它具有优先级15.换句话说,它具有与解除引用/间接运算符相同的优先级*。在表达式中*++ptr重要的是不优先:两个运营商的优先权相同。因此,关联性开始发生。前缀增量和间接运算符具有左右关联性。由于该关联性,操作数ptr将++在操作符更靠左边之前与最右边的操作符分组*。换句话说,表达式将被分组*(++ptr)。因此,与*ptr++但不同的原因一样,这*部分也将应用于++ptr零件的价值。那个价值是多少?前缀增量表达式的值是增量后操作数的值。这使它成为一个与后缀增量运算符截然不同的野兽。假设你有:int i = 7;printf ("%d\n", ++i);printf ("%d\n", i);输出将是:88...与我们在postfix运算符中看到的不同。同样,如果你有:const char* p = "Hello";printf ("%c ", *p);    // note space in format stringprintf ("%c ", *++p);  // value of ++p is p after the incrementprintf ("%c ", *p++);  // value of p++ is p before the incrementprintf ("%c ", *p);    // value of p has been incremented as a side effect of p++输出将是:H e e l                // good dog你明白为什么吗?现在我们进入您询问的第三个表达式,++*ptr。实际上,那是最狡猾的。两个运算符具有相同的优先级和左右关联性。这意味着表达式将被分组++(*ptr)。的++部分将被应用到的值*ptr的部分。所以如果我们有:char q[] = "Hello";char* p = q;printf ("%c", ++*p);令人惊讶的自我输出将是:I什么?!好的,所以该*p部分将评估为'H'。然后++进入游戏,此时,它将被应用于'H',而不是指针!添加1时会发生什么'H'?你得到1加上ASCII值'H'72; 你得到73.表示为a char,你得到charASCII值为73 : 'I'.这会照顾你在问题中提到的三个表达方式。这是您的问题的第一条评论中提到的另一条:(*ptr)++ 那个也很有意思。如果你有:char q[] = "Hello";char* p = q;printf ("%c", (*p)++);printf ("%c\n", *p);它会给你这个热情的输出:HI这是怎么回事?同样,这是优先级,表达值和副作用的问题。由于括号,该*p部分被视为主要表达式。主要表达方式胜过其他一切; 他们先得到评估。而且*p,如您所知,评估为'H'。表达式的其余部分(即++部分)将应用于该值。所以,在这种情况下,(*p)++成为'H'++。有什么价值'H'++?如果你说'I',你已经忘记了(已经!)我们对后缀增量的价值与副作用的讨论。请记住,'H'++评估当前的值 'H'。所以首先printf()打印'H'。然后,作为副作用,'H'将增加到'I'。第二个printf()打印出来'I'。你有愉快的问候。好的,但在最后两个案例中,我为什么需要char q[] = "Hello";char* p = q;为什么我不能有类似的东西/*const*/ char* p = "Hello";printf ("%c", ++*p);   // attempting to change string literal!因为"Hello"是字符串文字。如果您尝试++*p,则尝试'H'将字符串中的内容更改'I'为整个字符串"Iello"。在C中,字符串文字是只读的; 尝试修改它们会调用未定义的行为。"Iello"在英语中也是不确定的,但这只是巧合。相反,你不能拥有char p[] = "Hello";printf ("%c", *++p);  // attempting to modify value of array identifier!为什么不?因为在这个例子中,p是一个数组。数组不是可修改的l值; 你不能通过p前后增加或减少来改变点数,因为数组的名称就好像它是一个常量指针一样。(这不是它的实际情况;这只是一种方便的方式来看待它。)总而言之,以下是您询问的三件事:*ptr++   // effectively dereferences the pointer, then increments the pointer*++ptr   // effectively increments the pointer, then dereferences the pointer++*ptr   // effectively dereferences the pointer, then increments dereferenced value这里有第四个,和其他三个一样有趣:(*ptr)++ // effectively forces a dereference, then increments dereferenced value如果ptr实际上是数组标识符,则第一个和第二个将崩溃。如果ptr指向字符串文字,第三个和第四个将崩溃。你有它。我希望现在都是水晶。你是一个很棒的观众,我整个星期都会来这里。

隔江千里

假设ptr指向数组的第i个元素arr。*ptr++求值arr[i]并设置ptr为指向的第(i + 1)个元素arr。它相当于*(ptr++)。*++ptr设置ptr为指向的第(i + 1)个元素arr并进行求值arr[i+1]。它相当于*(++ptr)。++*ptr增加arr[i]1并评估其增加的价值; 指针ptr保持不变。它相当于++(*ptr)。还有一个,但你需要括号来写它:(*ptr)++增加arr[i]1并在增加之前评估其值; 指针ptr再次保持不变。其余的你可以弄清楚自己; @Jaguar也回答了这个问题。

慕丝7291255

*ptr++ : post increment a pointer ptr*++ptr : Pre Increment a pointer ptr++*ptr : preincrement the value at ptr location阅读此处有关预增量和后增量运算符的信息这将  Hello作为输出int main(){    const char *p = "Hello";    while(*p)         printf("%c",*p++);//Increment the pointer here     return 0;}
打开App,查看更多内容
随时随地看视频慕课网APP
我要回答