内存
将指针之前先得了解内存,每个内存单元存放八个比特位的内容,而计算机需要在内存中寻找信息,这就需要对内存进行编号了,那么那个编号就是地址。c语言中将这个地址称为指针。
地址和指针
&(取地址操作符)
在c语言中,程序的运行需要一定的存储空间,每个变量都会在内存中申请一块空间,c语言可以通过&符号取出此变量的地址。例如:
右边就是a的地址,在X64环境下地址是八个字节(六十四个比特位,16个十六进制位)。
注:c语言中用%p来打印该变量地址。
注:在x86环境下地址占四个字节,可以通过sizeof求解地址大小。
指针
指针是指向变量的一种类型。
那么如何定义指针类型呢?首先,指针变量指向的是一个地址,这是指针第一要素。其次,指针要能对这个地址的内容进行操作,那么就要设计一种机制取出里面的内容进行操作。最后,指针的取出的范围是多少字节这就还需要一种机制了。
以上三种条件确定了指针类型。
在c语言中由* 号确定这是一个指针类型,他的操作范围是int类型所占的字节或者还可以理解为他指向的类型是int类型,他指向的地址是a的地址(&a)。那么这些条件仅占用了两个条件,那么如何取出内部数据呢?
*(解引用操作符)
解引用操作符是将一个地址中的内容取出来。
上述是将pa地址中的变量取出来,pa中存放的是a的地址,那么就是将地址a中的变量取出。这就是*号的作用。
个人理解对于指针的理解
内存犹如按一定顺序的盒子,地址是盒子上所写的编号,指针是指向某个编号的变量,&号是将某个变量存放的盒子编号取出,*号是将一个编号盒子打开取出里面的内容。
而重要的是这个指针指向何处,指向的内容是什么,能操作多少内容。这个是指针最重要的三点,同时也是指针的定义了。
指针的一些运用
指针+-整数
指针+-整数是指针向后或向前跳过类型*整数个字节,这里因为pa是int类型(占4个字节)所以pa+1向后跳四个字节,pa-1同理向前跳四个字节。
以上就是指针+-整数的运算了。
指针-指针
上面是指针-指针的举例,指针-指针的结果是两个指针的内存差除以指针的类型,那么不同类型的指针相减呢?这里需要读者去自己测试寻找规律了。
注:指针+指针没有意义,这里作者就不做任何介绍。
特殊指针void*
在指针类型中有⼀种特殊的类型是 void* 类型的,可以理解为无具体类型的指针(或者叫泛型指
针),这种类型的指针可以⽤来接受任意类型地址。但是也有局限性, void* 类型的指针不能直接进行指针的+-整数和解引用的运算。
野指针
野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)
野指针是一种指针导致的问题,因为指针可以存放任何数据的地址,就可能导致指针指向一些不可更改的位置导致计算机系统损坏,当使用指针时应该避免出现野指针。也就是知道指针指向何处。
传值调用和传指调用
左图是传值调用,这里发现左图的a,b的值没有被改变。
这里可以通过看a和b的地址就可以看出a和传入的a的地址不同,函数内部是对传入数据的一份拷贝,而不是对传入数据进行修改。
而传指调用不会出现这种情况。
数组相关的指针
这里发现数组首元素地址和数组名地址相同,这里是数组第一个特性。
再次观察,发现&arr的地址和arr的地址也相同,那么&arr和arr以及&arr[0]有什么区别呢。
由上图可以看出&arr[0]和arr的效果是相同的,而&arr表示的是整个数组的地址,+1是跳过整个数组。
函数指针和数组指针
函数指针是指向函数的指针,数组指针是指向数组的指针。这两种类型比较复杂,这里仅举例
typedef对函数指针与数组指针的重定义
上面函数指针和数组指针的定义非常复杂,所以用typedef定义会大大简化操作。
上面函数指针的类型是int(*)(int,int)那么可以用typedef重定义int(*pfun_t)(int,int),pfun_t就是重定义类型,这样就大量简化了类型的描述。
最后,要深入理解指针的三要素,以及了解一些概率,对于指针的运用就能得心应手了。