【手把手带你入门】初级指针
学完了操作符,接下来我们就来讲一讲指针,很多人都说指针很难,指针学不懂,那么到底指针是什么呢?在初识C语言(下)中,我们已经对指针进行了初步的介绍,那么接下来,我们就用官方的解释来再认识一下指针吧~
什么是指针
在计算机科学中,指针(Pointer)是编程语言中的一个对象,利用地址,它的值直接指向(points to)存在电脑存储器中另一个地方的值。由于通过地址能找到所需的变量单元,可以说,地址指向该变量单元。因此,将地址形象化的称为“指针”。意思是通过它能找到以它为地址
的内存单元。
所以指针是一个变量,用来存放内存单元的地址。
我们之前已经讨论过,一个内存单元的大小是一个字节,所以在32位的机器上,地址的大小是4个字节,在64位的机器上,地址的大小是8个字节。(此处如有不明白,可转至这篇文章:初识C语言(下))
指针和指针类型
我们都知道,变量分为char、short、int等等类型,那么指针有没有类型呢?
答案是有的。
除了以上的int和char,指针的类型还有short*、long*、float*、double*等等。
指针类型告诉我们该指针指向的地址中存放的变量类型是什么。
指针类型的意义
那么指针类型的意义是什么呢?
指针的解引用
首先我们对指针进行解引用。
所以我们可以看到指针类型决定了指针解引用操作的时候,依次能访问几个字节。
指针加减整数
int指针+1 跳过四个字节
char指针+1 跳过1个字节
以上代码说明,指针类型决定了指针加减整数的时候的步长。
下面我们再来看看指针类型的应用。
从上面两段代码的调试中,我们可以看到,指针的类型可以帮助我们根据我们的需求访问空间里面的内容。
如果我想每次跳过1个字节,那我就用char指针,如果我想每次跳过4个字节,那我就用int指针。
综上,我们可以得出指针类型的意义就是:
指针的类型决定了对指针解引用的时候有多大的权限(能操作多少个字节)。
野指针
接下来我们介绍一个东西:野指针。
野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)。
即指针指向的空间是不属于我们的,如果这时候我们对之间进行解引用操作,就会出问题。
那么野指针是如何造成的呢?
野指针成因
指针没有初始化
造成野指针的第一个原因就是指针未初始化。
注意,上图中的p就是野指针。
指针越界访问
除了指针未初始化外,指针的越界访问也是造成野指针的一个原因。
假如我们不小心写了下面这样一段代码:
上图中的p原本不是野指针,但是当指针逐渐向后跳过10个整型时,它就变成了野指针。
当然,我们可以对这块不属于我们的空间进行访问,但是不能对它进行操作。
这就像我们可以在银行门口参观徘徊,但是不能进银行抢钱一样。
指针指向的空间被释放
还有一个原因也会造成野指针。
当我们运行程序:
这就好像小明住宾馆,住了一晚上之后就退了房,但是他把房间号记住了,第二天又去这个房间,发现里面还是一模一样。之所以一模一样只是因为房间还没有被打扫,但是小明因为已经把房退了,他就不能再回房间住了。
下面我们大致介绍一下为什么我们说这里p指向的空间被覆盖了。
如何规避野指针
那么我们作为程序员,应该如何避免写出野指针呢?
第一,对指针明确地初始化。
我们对NULL转到定义:
所以,理论上我们也可以把上面的代码写成:
第二,小心指针越界。
在写代码的时候,要注意检查写出的代码是否造成越界。
第三,当指针指向的空间被释放的时候就立即将它设置为NULL。
第四,尽量避免返回局部变量的地址。因为局部变量所在的空间一旦被释放,这个地址就无效了。
第五,在使用指针之前检查它的有效性。
那么既然NULL不能使用,为什么我们还要把它设置为NULL呢?
这就是为了提醒我们,这是一个空指针,是不能使用的。
这就好像我们在野外,可能会有人立块牌子告诉你,这是无人区,不要进入,可能会有野兽,强行进入是很危险的。这时候我们就知道了,这是一个无人区,不能随便进。
指针运算
接下来我们看看指针运算。
实际上,指针是可以进行运算。
指针的运算有一下几种:
- 指针±整数
- 指针-指针
- 指针的关系运算
- 指针的解引用操作
在这里我们对前三种进行介绍。
指针±整数
指针-指针
应用:
指针的关系运算
指针的关系运算就是比较指针的大小。
但是我们将上面代码进行简化:
上面这段简化的代码虽然看起来更加易懂,并且在大多数编译器上都能通过,但是我们还是应该避免这样写。
因为标准规定:
允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与指向第一个元素之前的那个内存位置的指针进行比较。
指针和数组
那么指针和数组有什么关系呢?
我们知道,数组是一块连续的空间,里面存放的是相同类型的元素。数组的大小和元素的类型以及元素的个数有关系。
而指针,是一个变量,里面存放的是地址。
而我们经常说:数组名是数组首元素的地址。
因为我们可以把数组名当成地址存放到一个指针中,所以我们能用指针来访问数组中的元素。
二级指针
指针变量也是变量,既然是变量就应该有地址,那指针变量的地址放在哪里呢?
答案就是二级指针。
那么有二级指针,有没有三级、四级指针呢?
答案是有的。
并且,我们可以发现:
同样地,我们对指针进行解引用。
**pp 就是先通过pp 找到 p,然后在通过p找到a。
指针数组
从名字来讲,指针数组其实指的是一个数组。
我们知道:
int arr[10] - 整形数组 - 存放整型的数组
char ch[5] - 字符数组 - 存放字符的数组
那么以此类推,指针数组就应该是用来存放指针的数组。
int* parr[5] - 整型指针数组 - 存放整型指针
char* pch[6] - 字符指针数组 - 存放字符指针
那么指针数组有什么用呢?
对于指针的基本使用就讲到这里啦!
有没有觉得指针其实真的没有想象中的那么难!
不管你觉得指针难不难,都记得要给辛苦码文的博主我点个赞哦~也欢迎你来评论区与我交流!
虽然今天我们只是对指针进行初步的讲解,但是我们已经能够很好地使用指针啦~
当然后面我们还会有对指针更加深入的讲解,希望大家多多期待噢~
关注我,学习更多C语言知识!
本文相关代码已上传至Gitee,各位按需自取噢~