[英]How to explain C pointers (declaration vs. unary operators) to a beginner?
[英]How does unary addition on C pointers work?
我知道一元运算符++将一个加到一个数字上。 但是,我发现如果我在一个int指针上执行它,它会递增4(我的系统上的int的sizeof)。 为什么这样做? 例如,以下代码:
int main(void)
{
int *a = malloc(5 * sizeof(int));
a[0] = 42;
a[1] = 42;
a[2] = 42;
a[3] = 42;
a[4] = 42;
printf("%p\n", a);
printf("%p\n", ++a);
printf("%p\n", ++a);
return 0;
}
将返回三个数字,每个数字之间相差4。
这就是C的方式 - 完整的解释在规范中, 第6.5.6节“附加算子” ,第8段:
当一个具有整数类型的表达式被添加到指针或从指针中减去时,结果具有指针操作数的类型。 如果指针操作数指向数组对象的元素,并且数组足够大,则结果指向偏离原始元素的元素,使得结果元素和原始数组元素的下标的差异等于整数表达式。 -th and i − -th elements of the array object, provided they exist. 换句话说,如果表达式
P
指向数组对象的第i个元素,则表达式(P)+N
(等效地,N+(P)
)和(P)-N
(其中N
具有值n )指向分别为数组对象的第i + 和第i - 个元素,只要它们存在即可。 此外,如果表达式P
指向数组对象的最后一个元素,则表达式(P)+1
指向一个超过数组对象的最后一个元素,如果表达式Q
指向一个超过数组对象的最后一个元素,表达式(Q)-1
指向数组对象的最后一个元素。 如果指针操作数和结果都指向同一个数组对象的元素,或者指向数组对象的最后一个元素,则评估不应产生溢出; 否则,行为未定义。 如果结果指向数组对象的最后一个元素之后,则不应将其用作已计算的一元*
运算符的操作数。
要将它与您使用前缀++
运算符联系起来,您还需要阅读第6.5.3.1节“前缀增量和减量运算符” ,第2段:
前缀
++
运算符的操作数的值递增。 结果是增量后操作数的新值。 表达式++E
等价于(E+=1)
。
第6.5.16.2节“复合转让 ”第3段:
E1
op= E2
形式的复合赋值与简单赋值表达式E1 = E1
op(E2)
仅在于左值E1
仅被评估一次。
它将指针位置增加int
的大小,即指针的声明类型。
请记住, int *
只是指向内存中某个位置的指针,您可以在其中存储“int”。 当你指向++
,它会将它移动一个位置(按类型的大小),在这种情况下,它会使你的值“4”更高,因为sizeof(int)==4
。
这样做的原因是使以下陈述成立:
*(ptr + n) == ptr[n]
这些可以互换使用。
因为在“C”中,指针算术总是按指向的对象的大小进行缩放。 如果你仔细想一想,事实证明这是“正确的事情”。
它这样做是为了让你不开始访问它中间的整数。
因为指针不是引用;)。 它不是一个值,它只是内存中的一个地址。 检查指针的值时,它将是一个数字,可能很大,与存储在该存储器位置的实际值无关。 比如, printf("%p\\n", a);
打印“2000000” - 这意味着您的指针指向机器内存中的第2000000个字节。 它几乎没有意识到它存储在什么价值。
现在,指针知道它指向的类型。 在您的情况下为整数。 由于一个整数是4个字节长,当你想要跳转到指针所指向的下一个“单元格”时,它需要是2000004.这是1个整数,所以a++
非常有意义。
顺便说一句,如果你想获得42
(从你的例子),打印出指向的值: printf("%d\\n", *a);
我希望这是有道理的 ;)
这很简单,因为它归结为指针,在你的情况下是一个整数指针,一元增量意味着由一个单元增加内存位置,其中一个单元=整数的大小。
这个整数大小取决于从编译到编译器,对于32位和16位,它是4字节,而对于64位编译器,它是8字节。
尝试使用字符数据类型执行相同的程序,当字符占用1个字节时,它将给出1个字节的差异。
简而言之,您遇到的4的差异是内存中SIZE OF ONE INTEGER的差异。
希望这有所帮助,如果不是,我会很乐意帮助我告诉我。
“为什么这样做?” 为什么你会期望它做任何其他事情? 递增一个点使它指向它指向的类型的下一个项目。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.