指针的基本运算主要分三种,分别是: 1,指针±整数 2,指针-指针 3,指针的关系运算
因为数组元素在内存中是连续存放的,那么,我们能不能通过【首地址+偏移量】的方式来得到其他元素的地址呢? 答案是可以的,比如下面的代码:
int main()
{
int arr[5] = { 1,2,3,4,5 };
int* p = &arr[0]; //取出首元素的地址放入指针p
for (int i = 0; i < 5; i++)
{
printf("%d ", *(p + i)); //(p+i)就是(指针+整数)的形式
}
}
输出结果是: 1 2 3 4 5
也就是说: (p+i)所代表的地址,随着i每次加1,地址也跳跃到了后面的元素 所以: **指针±整数**就是:以指针为首地址,来计算出偏移量为整数的元素的地址,让指针实现向前和向后的跳跃。
前提条件:两个指针必须指向同一块空间(比如,同一个数组) 来看下面代码:
int main()
{
int arr[5] = { 1,2,3,4,5 };
int* p1 = &arr[0]; //p1存放的是第一个元素的地址
int* p2 = &arr[4]; //p2存放的是最后一个元素的地址
printf("p1 = %p\n", p1); //打印指针p1的内容
printf("p2 = %p\n", p2); //打印指针p2的内容
printf("p2 - p1 = %d\n", p2 - p1); //大地址-小地址
printf("p1 - p2 = %d\n", p1 - p2); //小地址-大地址
return 0;
}
输出结果:
我们可以发现: 虽然指针是用16进制数来表示的,但是输出结果并不是将两个16进制数单纯的进行加减运算,输出结果也并不是一个指针。 实际上,指针-指针的绝对值是:指针之间元素的个数
对于指针±整数,指针-指针我们可以类比理解: 日期±天数:得到的是日期 日期-日期:得到的是天数 (在这里,日期就好比地址,天数就好比整数)
其实就是指针的大小比较,例如:
int main()
{
int arr[5] = { 1,2,3,4,5 };
int* p = &arr[0];
while (p < arr + 5) //这里就是比较p和arr+5的(16进制数)大小
{
printf("%d ", *p);
p++;
}
return 0;
}
输出结果是: 1 2 3 4 5
指针的解引用权限通俗来讲就是:一次性能操作几个字节。
我们来看下面两段代码:
两段代码都是通过对指针解引用来操作n,给n赋值。区别在于左边的指针变量是int* 类型,但是右边的指针变量是char*类型
我们在调试时观察n的变化:
发现: 用 int* 类型的指针变量时,n被完全改成了0(其实被改了4个字节): 从 0x11223344 → 0x00000000 用 char*类型的指针变量时,n只被改了一部分(其实被改了1个字节): 从 0x11223344 → 0x11223300 这就是为什么图左的n值减少了120(转换为10进制)
上述现象都是因为:指针变量的类型决定了指针解引用的权限 char* 的指针解引用只能一次访问1个字节,但是int* 的指针解引用就可以访问4个字节 同理: double* 可以访问8个字节 short* 可以访问2个字节
来看下面的代码:
int main()
{
int n = 10;
char* p1 = (char*)&n;
int* p2 = &n;
printf("&n = %p\n", &n);
printf("p1 = %p\n", p1);
printf("p1+1 = %p\n", p1+1);
printf("p2 = %p\n", p2);
printf("p2+1 = %p\n",p2+1);
return 0;
}
运行结果,我们观察地址的变化:
我们发现: 对于char* 类型的指针变量p1,+1操作让地址向后跳过了1个字节 对于int* 类型的指针变量p2,+1操作跳过了让地址向后跳过了4个字节
这就是指针变量类型不同对指针±整数的影响: 指针变量的类型决定了指针向前或者向后走一步的距离(跳过的字节的大小)