指针是C语言的一个重要的组成部分,是 C语言的核心、精髓所在,用好指针,可以在C语言的编程中起到事半功倍的效果。一方面,可以提高程序的编译效率和执行速度以及实现动态内存的分配。使用指针可以使程序更加的灵活,便于表示各种数据结构,编写高质量的程序。
今天我们就来讨论一下指针里面比较难的部分:指针的算术运算。
和其他的普通变量一样,指针本质上也是一个变量,如果把指针称作地址变量,这样就很容易理解指针了。普通的变量可以进行加减运算,类似的,指针也可以进行加减运算。但是指针的加减运算又不同于普通的变量那样进行简单的加某一个数或者减某一个数。
首先来看一下指针的加法:
(1)指针+数字:
int main()
{
int *p = (int *)2000;
printf("%d\n",p+4);//2016
printf("%d\n",(short *)p+4);//2008
printf("%d\n",(double *)p+4);//2032
printf("%d\n",(float **)p+4);//2016
printf("%d\n",(unsigned short *)p+4);//2008
printf("%d\n",(long *)p+4);//2016
printf("%d\n",(char *)p+4);//2004
printf("%d\n",(unsigned long long)p+4);//2004
return 0;
}
定义了一个整形的指针变量,由此结果可以看出,在进行指针的加法的时候,加的数字,需要调整,调整的权重就是sizeof(指针去掉一个*),简单来说,就是将指针的的*去掉一个,只需要去掉一个就好了,再看剩下的部分是什么类型。如果还是一个指针,那调整的权重就是4或者8.(如果是32位的系统,指针的大小就是4,64位的系统,指针的大小就是8).short类型的就是两个字节,则调整的权重就是两个字节,double类型的是8个字节,调整的权重就是8.以此类推。但是需要我们注意的是:最后一个的类型可不是指针哦,而是直接把指针类型的变量直接强制转换为无符号的long long类型,此时他就是一个普通的数字,所以最后一个进行的就是数字的加法,直接用2000加上4,结果就是2004.所以在解决问题的时候,需要我们擦亮眼睛,认真的读题审题,抠细节,才能够成功。
(2)指针 - 数字:
指针的加法解决了,现在需要解决的问题就是指针的减法,指针的减法和指针的加法都是大同小异的。
int main()
{
int *p = (int *)0x2010;
printf("%x\n",p-2);//2008
printf("%x\n",(short *)p-2);//200c
printf("%x\n",(unsigned long *)p-2);//2008
printf("%x\n",(long long **)p-2);//2008
printf("%x\n",(float *)p-2);//2008
printf("%x\n",(double *)p-2);//2000
printf("%x\n",(char *)p-2);//200e
printf("%x\n",(unsigned long )p-2);//200e
return 0;
}
这里首先定义了一个指针变量为ox2010,虽然是16进制,但是在输出的时候,也要求我们输出16进制,所以就不用进行数制之间的转换,直接输出16进制就好了。这道题我们也很容易的用类似于加法的算术规则进行运算,就可以得出答案。但是在这里需要注意的就是16进制之间的加减运算。十六进制和十进制类似,只是本位上数值不够的时候,需要上一位借位16,然后在进行加减运算。同时需要注意的是,最后一位并不是指针,而是一个无符号类型的long类型的数据,在运算的时候,直接按照数字的运算进行就好了。
(3)指针+指针 指针-指针
指针可以加数字,那么指针可以加指针吗,可以减指针吗?
我们先来考虑一个这样的问题,2018年+2017年是一个什么样的结果,按照正常的思维去考虑,我们感觉他是没有什么实际意义的,所以在C语言里面,指针加指针是非法的。那么指针可以减指针吗?
还是同样的问题,2018年-2017年表示的是什么意义呢?,按照正常的思维,2018年-2017年就是指的是2018年和2017年之间相差几年,其结果是1 ,也就是相差了1。8月-7月也表示的是8月份与7月份之间相差了1个月,其答案是相同的,但是单位是不相同的,也就是说它们之间的单位也是不停的在调整的,由此我们可以得出以下的规律:指针-指针表示指针之间间隔的单元个数,具体方法为:1、算出字节数;2、除以调整权重。我们来看一段代码你就会懂了。
int main()
{
int arr[10] = {0};//x
int *p = &arr[9];//x+36
int *q = &arr[1];//x+4
printf("%d\n",p-q);//8
printf("%d\n",q-p);//-8
printf("%d\n",(short *)p-(short *)q);//16
printf("%d\n",(long *)p-(long *)q);//8
printf("%d\n",(char **)p-(char **)q);//8
printf("%d\n",(double *)p-(double *)q);//4
printf("%d\n",(long long)p-(long long)q);//32
printf("%d\n",(char *)p-(char *)q); //32
return 0;
}
我们首先定义了一个长的为10的数组,其中首元素是0,其余都是\0,再定义了一个地址变量p保存的是9号下标,定义了地址变量q保存的是1号下标,然后让我们来求的是指针的减法。根据上面的规律,我们首先求出之间间隔的字节数,因为定义的是整型的数组,所以p的字节数为36,而q的字节数为4.两个相减就是其相差的字节数大小也就是32,其他的按照调整的权重进行相减就好了。
(short *)p - (short *)q:(short *)去掉一个*就是short,占2个字节,32/2=16;
(long *)p-(long *)q : (long *)去掉一个*就是long ,占4个字节,32/4=8;
(char **)p-(char **)q : (char **)去掉一个*就是char* ,指针占了4个字节,32/4=8;
(long long)p - (long long )q : 括号里面是(long long)类型,也就是直接强转为了(long long)类型,没有*可以去,所以直接就是数字的减法。
(char *)p-(char *)q :去掉一个*后是一个char类型,占一个字节,32/1=32;
这些就是指针的算数运算,我们在实际的编程中需要注意。