指针运算的核心规则是“指针类型决定步长”,即指针加减整数时按其所指数据类型的大小进行偏移,而非简单的地址数值加减;例如int指针加1会增加4字节(假设int为4字节),char指针加1则增加1字节,因此ptr + n的实际地址变化为n * sizeof(所指类型);这种机制使得指针能正确遍历数组元素,如int数组首地址为0x1000时,p + 1指向0x1004,p + 2指向0x1008;同类型指针可相减得到其间元素个数,如&arr[3] – &arr[1]结果为2,表示相隔两个int元素;但指针之间不能相加,因无实际意义且被编译器禁止;理解类型决定步长是掌握指针算术的关键所在。
指针运算的核心规则和地址加减的实际含义,关键在于理解“指针类型决定步长”这一点。它不是简单的数值加减,而是基于数据类型大小的偏移。
指针与整数的加减运算
当你对指针进行加减一个整数的操作时,比如
ptr + n
或
ptr - n
,编译器并不会简单地将指针的地址值加上或减去
n
,而是会乘以该指针所指向数据类型的大小。
-
ptr + n
ptr
向后移动
n
个“目标数据类型单位”。实际地址增加的字节数是
n * sizeof(指针所指向的数据类型)
。
-
ptr - n
ptr
向前移动
n
个“目标数据类型单位”。实际地址减少的字节数是
n * sizeof(指针所指向的数据类型)
。
实际含义与例子
这种设计的目的是让指针能够方便地遍历数组或访问连续内存中的同类数据。加减运算的结果是另一个指向同类型数据的指针。
假设有一个
int
类型的数组,
int arr[5] = {10, 20, 30, 40, 50};
,并且
int *p = arr;
(即
p
指向数组第一个元素
arr[0]
)。
-
p + 1
的结果是指向
arr[1]
的指针。
- 如果
p
的值是
0x1000
(假设
int
占 4 字节),那么
p + 1
的值是
0x1000 + (1 * 4) = 0x1004
。
- 如果
-
p + 2
的结果是指向
arr[2]
的指针。
- 地址计算:
0x1000 + (2 * 4) = 0x1008
。
- 地址计算:
-
p - 1
的结果是指向
arr[-1]
的指针(如果存在且合法)。
- 地址计算:
0x1000 - (1 * 4) = 0x0FFC
。
- 地址计算:
不同类型指针的步长
不同数据类型大小不同,因此指针加减的“步长”也不同。
- *`char
指针**:
char
通常占 1 字节。
ptr_char + 1` 会使地址增加 1 个字节。
- *`short
指针**:
short
通常占 2 字节。
ptr_short + 1` 会使地址增加 2 个字节。
- *`int
指针**:
int
通常占 4 字节。
ptr_int + 1` 会使地址增加 4 个字节。
- *`double
指针**:
double
通常占 8 字节。
ptr_double + 1` 会使地址增加 8 个字节。
指针之间的减法
两个同类型指针可以相减(
ptr1 - ptr2
),其结果是一个
ptrdiff_t
类型的整数,表示两个指针之间相隔多少个“目标数据类型单位”。
- 这个操作通常用于计算数组中两个元素之间的距离。
- 例如,
&arr[3] - &arr[1]
的结果是
2
,表示它们之间相隔 2 个
int
元素。
- 实际地址差是
2 * sizeof(int) = 8
字节(假设
int
为 4 字节)。
指针之间的加法
两个指针不能直接相加(
ptr1 + ptr2
是非法操作)。这没有明确的语义,编译器会报错。
基本上就这些,理解“类型决定步长”是掌握指针算术的关键。