让int * ptr,array[10]; ptr= array;
. 现在,阵列连续位置中的每个存储单元都有固定的大小。如果第一个单元格的地址是 1234,那么下一个单元格的地址必须是 1238。但是我们使用指针作为访问它*(ptr+1)
。我对此感到困惑。任何来源或答案?谢谢。
8 回答
来自 C11标准: §6.5.2.1
后缀表达式后跟方括号 [] 中的表达式是数组对象元素的下标指定。下标运算符 [] 的定义是 E1[E2] 等同于 (*((E1)+(E2)))。由于适用于二元 + 运算符的转换规则,如果 E1 是数组对象(等效地,指向数组对象的初始元素的指针)并且 E2 是整数,则 E1[E2] 指定第 E2 个元素E1(从零开始计数)。
EG 你正在做的基本上是[]
已经做的
此外(相同的标准)解释了为什么指针会像您注意到的那样增加:§6.5.6
当一个整数类型的表达式被添加到指针或从指针中减去时,结果具有指针操作数的类型。如果指针操作数指向数组对象的元素,并且数组足够大,则结果指向与原始元素偏移的元素,使得结果和原始数组元素的下标之差等于整数表达式。换句话说,如果表达式 P 指向数组对象的第 i 个元素,则表达式 (P)+N(等效于 N+(P))和 (P)-N(其中 N 的值为 n)指向分别到数组对象的第 i+n 个和第 i-n 个元素,前提是它们存在。此外,如果表达式 P 指向数组对象的最后一个元素,则表达式 (P)+1 指向数组对象的最后一个元素,如果表达式 Q 指向数组对象的最后一个元素,则表达式 (Q)-1 指向数组对象的最后一个元素。如果指针操作数和结果都指向同一个数组对象的元素,或者超过数组对象的最后一个元素,则计算不应产生溢出;否则,行为是未定义的。如果结果指向数组对象的最后一个元素,则不应将其用作计算的一元 * 运算符的操作数。行为未定义。如果结果指向数组对象的最后一个元素,则不应将其用作计算的一元 * 运算符的操作数。行为未定义。如果结果指向数组对象的最后一个元素,则不应将其用作计算的一元 * 运算符的操作数。
编译器知道这ptr
是一个指向 4 字节类型的指针,因此它知道它ptr+1
在内存中还有 4 个字节。
如果您想一想,很明显必须如此,否则您将无法在不知道系统上(例如)整数大小的情况下编写可移植代码。
此外,数组索引在幕后完全是指针运算 - 也就是说,array[3]
与*(array + 3)
当索引一个指针时,编译器知道索引应该提前单元格的大小,在这种情况下,一个 4 字节的指针。
指针算法考虑了指向类型的大小。例如,如果 的值为ptr
,1234
因为ptr
is 的类型为int*
,那么 的值为p + 1
(1234 + 1 * sizeof(int) == 1234 + 1 * 4 = 1238
假设sizeof(int) == 4
)。
指针算术与普通算术不同。在指针算术中,一个参数必须是指针类型,另一个必须是整数类型:
intA + intB
: 普通算术,结果是总和。intA + pointerB
: 指针运算,执行的计算是sizeof(*pointerB)*intA + pointerB
pointerA + intB
: 指针运算,执行的计算是pointerA + sizeof(*pointerA)*intB
pointerA + pointerB
: 非法的
pointerA[intB]
只是 case 2 ( pointerA + intB
) 的简写,这就是为什么它等同于intB[pointerA]
(resolves to case 3),但这仅在 IOCCC 中使用。
+ 运算符的右操作数,我们称之为 x,并不是您移动指针的实际量。因为 int 是 4 个字节,编译器知道实际跳到 x*4。
我的猜测是,根据你 (ptr + 1)
应该给你1235
,但显然它没有。
除了其他人给出的关于它为什么添加4
和给你的答案之外1238
,考虑一下它给你的情况1235
,1235
你没有整数元素(即数组的第二个元素)。但是你的指针应该指向一个整数。因此,这种方式行不通。
指针算术的单位是指向对象,而不是字节。
如果p
指向int
对象,则p+1
、p+2
和p+3
指向连续的int
对象,而不是连续的字节。如果p
指向一个大型结构,则它们指向该结构的连续实例。
编译器在幕后进行工作,将指针算术转换为机器地址算术。因此,它根据需要将偏移量相乘,以将对象单位转换为字节单位。