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
,你得到char
ASCII值为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)