1.指针加减整数
指针加减整数并不是简单的地址加减。在计算机内存中,每个变量都有一个唯一的存储位置,这个位置由其地址表示。当你对指针执行加法或减法操作,并传递一个整数值,实际上是改变了指针指向的位置,使其指向新的地址。这个新地址通常对应于原来地址基础上增加或减少指定的字节数,这取决于所使用的数据类型(比如int、char等)的大小。
举个例子,
如果你有一个指向整数的指针,将它加上一个整数意味着指针会移动相应整数的字节数。
而如果是在C/C++这样的语言中,数组下标运算本质上也是通过这种指针加减来实现的,因为数组名就是一个常量指针,数组元素可以通过指针算术访问。
我们通过下面一段代码来解释:
#include<stdio.h>
int main()
{
int arr[9]={1,2,3,4,5,6,7,8,9};
int *p=arr;
for(int i=0;i<9;i++)
{
printf("%d ",*p);
p++;
}
return 0;
}
在这段代码中,我们定义了一个整形数组arr[9]并将其初始化,接着我们定义了一个整形指针变量p并将数组首元素的地址赋值给了p,那么指针指向的内容就是数组的首元素,接着通过for循环输出打印数组元素,在每次打印完数组元素后将p++。
输出显示结果:
首先我们要知道
地址变量+整数是原地址加上整数*sizeof(int)个字节
因为p++其实就是p=p+1,又因为p是整形指针变量,所以p+1就是在p存储的地址上增加四个字节。因此代码中每执行一次for循环,都会让指针变量p的地址增加四个字节,由于数组的存储是连续的,所以每次循环,指针都会指向数组的下一个元素
2.指针减指针
指针减指针的绝对值是指针与指针之间的元素个数(该运算实现的前提是两个指针指向同一个空间)
有下面一串代码:
#include<stdio.h>
int main()
{
int arr[9]={1,2,3,4,5,6,7,8,9};//定义一个整形数组;
int sz=sizeof(arr)/sizeof(arr[0]);//计算数组元素个数;
int *p=&arr[0];//定义一个整形指针变量并初始化;
int *q=&arr[sz-1];
printf("%d",q-p);
return 0;
}
打印输出的结果为8,也就是p与q之前有8个元素,我们再用图示来解释:
p中存储的是arr[0]的地址,q存储的是arr[8]的地址,所以指针q-指针p之间的元素个数为8.
3.指针间的关系运算
指针间的关系运算其实就是指针间的大小比较,我们定义一个数组,随着下标的增长,地址是由低到高的,那么下面我们通过进行指针的大小比较来将数组元素的值增加1并将其输出打印:
#include<stdio.h>
int main()
{
int arr[9]={1,2,3,4,5,6,7,8,9};//定义一个整形数组并将其初始化
int sz=sizeof(arr)/sizeof(arr[0]);//计算数组元素个数
int *p=&arr;//定义一个整形指针并将数组首地址赋值给指针变量p
int *q=&arr[sz-1];//定义一个整形指针并将数组最后一个元素的地址赋值给q
while(p<=q)//判断p<=q是否为真,为真执行下面语句,为假,跳出while语句
{
(*p)++;//每次将数组的元素值加1
printf("%d ",*p);//每次打印数组的元素
p++;//将p的地址增加四个字节使其存储下一个数组元素的地址
}
return 0;
}
该代码输出打印的结果:
指针加指针这个操作通常是指两个指针相加,但在某些编程语言和上下文中,并非所有指针都适合直接相加。主要有以下几个原因:
1.不同类型: 如果指针不是同一种数据类型的地址,比如一个是整数指针,另一个是字符指针,直接相加就没有意义了,因为它们代表的内存位置和偏移量单位不一样。
2。空指针处理: 空指针(NULL或nullptr)没有实际的地址,当你试图对空指针加值时,会引发运行时错误,因为这种操作试图访问无效的内存地址。
3.指针指向的数据结构: 对于复杂数据结构如数组、字符串等,内部元素的地址可能是连续的,但是相邻元素之间的指针相加可能并不表示有效的元素间跳跃,除非明确知道数据结构的具体规则。
4.未初始化指针: 直接对未初始化的指针进行加法运算可能导致不可预知的结果,因为它们尚未指向任何有效的内存地址。
5.特定库的操作限制: 一些高级编程语言或库可能会有特定的指针处理机制,不允许或者限制普通指针间的简单相加。因此,在设计程序时,需要根据具体情况判断是否可以安全地对指针进行加法操作,或者使用指针算术运算符来处理