all*_*ted 117 c c++ pointers increment
最近我遇到了这个我自己无法理解的问题.
这三个表达式真正意味着什么?
*ptr++
*++ptr
++*ptr
Run Code Online (Sandbox Code Playgroud)
我试过里奇.但不幸的是,他无法按照他讲述的这三项行动.
我知道它们都是为了递增指针/指向的值而执行的.我还可以猜测可能有很多关于优先级和评估顺序的事情.就像一个指针首先递增指针然后取出指针的内容,一个简单地取出内容然后递增指针等等.正如你所看到的,我对他们的实际操作我没有清楚的理解,我想尽快明确.但是当我有机会将它们应用到程序中时,我真的迷失了.例如:
int main()
{
const char *p = "Hello";
while(*p++)
printf("%c",*p);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
给我这个输出:
ello
Run Code Online (Sandbox Code Playgroud)
但我的期望是它会印刷Hello.最后一个请求 - 请给出一些示例,说明每个表达式在给定的代码段中的工作原理.因为大多数时候只有一段理论飞过我的脑海.
ver*_*ose 254
这是一个详细的解释,我希望对此有所帮助.让我们从您的程序开始,因为它是最简单的解释.
int main()
{
const char *p = "Hello";
while(*p++)
printf("%c",*p);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
第一个声明:
const char* p = "Hello";
Run Code Online (Sandbox Code Playgroud)
声明p为指向char.当我们说"指向一个char"时,这是什么意思?这意味着值p是a的地址char; p告诉我们在记忆中哪里留有一些空间来容纳一个char.
该语句还初始化p为指向字符串文字中的第一个字符"Hello".为了这个练习,重要的是理解p为不指向整个字符串,而只指向第一个字符'H'.毕竟,p是一个指针char,而不是整个字符串.值p是'H'in 的地址"Hello".
然后你设置一个循环:
while (*p++)
Run Code Online (Sandbox Code Playgroud)
循环条件*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);
Run Code Online (Sandbox Code Playgroud)
输出将是:
7
8
Run Code Online (Sandbox Code Playgroud)
因为在增量之前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);
Run Code Online (Sandbox Code Playgroud)
如前所述,输出将是:
7
8
Run Code Online (Sandbox Code Playgroud)
当i++在第一评估printf()中,评估为7.但C标准保证在之前所述第二某点printf()处开始执行,在副作用的的++操作员将已经发生.也就是说,在第二次printf()发生之前,i由于++第一次运算符的结果将增加printf().顺便说一下,这是标准给出的关于副作用时间的少数保证之一.
然后,在您的代码中,当计算表达式时*p++,它的计算结果为'H'.但到了这个时候:
printf ("%c", *p)
Run Code Online (Sandbox Code Playgroud)
发生了令人讨厌的副作用.p已增加.哇!它不再指向'H',而是指过去的一个角色'H':'e'换句话说.这解释了你的cockneyfied输出:
ello
Run Code Online (Sandbox Code Playgroud)
因此,在其他答案中的有用(和准确)建议的合唱:打印收到的发音"Hello"而不是它的cockney对应,你需要类似的东西
while (*p)
printf ("%c", *p++);
Run Code Online (Sandbox Code Playgroud)
这么多.剩下的呢?你问这些意义:
*ptr++
*++ptr
++*ptr
Run Code Online (Sandbox Code Playgroud)
我们刚才谈到了第一个,所以让我们来看看第二个:*++ptr.
我们在前面的解释中看到,后缀增量p++具有一定的优先级,值和副作用.前缀增量++p具有与其后缀对应物相同的副作用:它将其操作数增加1.但是,它具有不同的优先级和不同的值.
前缀增量的优先级低于后缀; 它具有优先级15.换句话说,它具有与解除引用/间接运算符相同的优先级*.在表达式中
*++ptr
Run Code Online (Sandbox Code Playgroud)
重要的是不优先:两个运营商的优先权相同.因此,关联性开始发生.前缀增量和间接运算符具有左右关联性.由于该关联性,操作数ptr将++在操作符更靠左边之前与最右边的操作符分组*.换句话说,表达式将被分组*(++ptr).因此,与*ptr++但不同的原因一样,这*部分也将应用于++ptr零件的价值.
那个价值是多少?前缀增量表达式的值是增量后操作数的值.这使它成为一个与后缀增量运算符截然不同的野兽.假设你有:
int i = 7;
printf ("%d\n", ++i);
printf ("%d\n", i);
Run Code Online (Sandbox Code Playgroud)
输出将是:
8
8
Run Code Online (Sandbox Code Playgroud)
...与我们在postfix运算符中看到的不同.同样,如果你有:
const char* p = "Hello";
printf ("%c ", *p); // note space in format string
printf ("%c ", *++p); // value of ++p is p after the increment
printf ("%c ", *p++); // value of p++ is p before the increment
printf ("%c ", *p); // value of p has been incremented as a side effect of p++
Run Code Online (Sandbox Code Playgroud)
输出将是:
H e e l // good dog
Run Code Online (Sandbox Code Playgroud)
你明白为什么吗?
现在我们进入您询问的第三个表达式,++*ptr.实际上,那是最狡猾的.两个运算符具有相同的优先级和左右关联性.这意味着表达式将被分组++(*ptr).的++部分将被应用到的值*ptr的部分.
所以如果我们有:
char q[] = "Hello";
char* p = q;
printf ("%c", ++*p);
Run Code Online (Sandbox Code Playgroud)
令人惊讶的自我输出将是:
I
Run Code Online (Sandbox Code Playgroud)
什么?!好的,所以该*p部分将评估为'H'.然后++进入游戏,此时,它将被应用于'H',而不是指针!添加1时会发生什么'H'?你得到1加上ASCII值'H'72; 你得到73.表示为a char,你得到charASCII值为73 : 'I'.
这会照顾你在问题中提到的三个表达方式.这是您的问题的第一条评论中提到的另一条:
(*ptr)++
Run Code Online (Sandbox Code Playgroud)
那个也很有意思.如果你有:
char q[] = "Hello";
char* p = q;
printf ("%c", (*p)++);
printf ("%c\n", *p);
Run Code Online (Sandbox Code Playgroud)
它会给你这个热情的输出:
HI
Run Code Online (Sandbox Code Playgroud)
这是怎么回事?同样,这是优先级,表达值和副作用的问题.由于括号,该*p部分被视为主要表达式.主要表达方式胜过其他一切; 他们先得到评估.而且*p,如您所知,评估为'H'.表达式的其余部分(即++部分)将应用于该值.所以,在这种情况下,(*p)++成为'H'++.
有什么价值'H'++?如果你说'I',你已经忘记了(已经!)我们对后缀增量的价值与副作用的讨论.请记住,'H'++评估当前的值 'H'.所以首先printf()打印'H'.然后,作为副作用,'H'将增加到'I'.第二个printf()打印出来'I'.你有愉快的问候.
好的,但在最后两个案例中,我为什么需要
char q[] = "Hello";
char* p = q;
Run Code Online (Sandbox Code Playgroud)
为什么我不能有类似的东西
/*const*/ char* p = "Hello";
printf ("%c", ++*p); // attempting to change string literal!
Run Code Online (Sandbox Code Playgroud)
因为"Hello"是字符串文字.如果您尝试++*p,则尝试'H'将字符串中的内容更改'I'为整个字符串"Iello".在C中,字符串文字是只读的; 尝试修改它们会调用未定义的行为."Iello"在英语中也是不确定的,但这只是巧合.
相反,你不能拥有
char p[] = "Hello";
printf ("%c", *++p); // attempting to modify value of array identifier!
Run Code Online (Sandbox Code Playgroud)
为什么不?因为在这个例子中,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
Run Code Online (Sandbox Code Playgroud)
这是第四个,与其他三个一样有趣:
(*ptr)++ // effectively forces a dereference, then increments dereferenced value
Run Code Online (Sandbox Code Playgroud)
如果ptr实际上是数组标识符,则第一个和第二个将崩溃.如果ptr指向字符串文字,第三个和第四个将崩溃.
你有它.我希望现在都是水晶.你是一个很棒的观众,我整个星期都会来这里.
nic*_*kie 43
假设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也回答了这个问题.
Jai*_*dra 13
*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;
}
Run Code Online (Sandbox Code Playgroud)
循环中的条件很糟糕:
while(*p++)
printf("%c",*p);
Run Code Online (Sandbox Code Playgroud)
是相同的
while(*p)
{
p++;
printf("%c",*p);
}
Run Code Online (Sandbox Code Playgroud)
这是错的,这应该是:
while(*p)
{
printf("%c",*p);
p++;
}
Run Code Online (Sandbox Code Playgroud)
*ptr++是一样的*(ptr++),这是:
const char *ptr = "example";
char value;
value = *ptr;
++ptr;
printf("%c", value); // will print 'e'
Run Code Online (Sandbox Code Playgroud)
*++ptr是一样的*(++ptr),这是:
const char *ptr = "example";
char value;
++ptr;
value = *ptr;
printf("%c", value); // will print 'x'
Run Code Online (Sandbox Code Playgroud)
++*ptr是一样的++(*ptr),这是:
const char *ptr = "example";
char value;
value = *ptr;
++value;
printf("%c", value); // will print 'f' ('e' + 1)
Run Code Online (Sandbox Code Playgroud)