指针
可以毫不夸张地说C语言的指针使C语言有了灵魂,C语言的指针是使C语言变得强大的一个重要工具,引用《c和指针》这本书上的一句话“正是指针使C语言威力无穷。有些任务用其他语言也可以实现,但C语言能够更加有效地实现;有些任务无法用其它语言实现,如直接访问硬件,但C语言却可以;”
C语言指针虽然强大但是与之相伴的风险却也不小,使用的得当可以使程序变得高效,但是如果使用的不得当,导致的细微而令人困惑的症状,也是很难发现的,所以我们要想学好C语言指针不能不一知半解。
指针的概念:
我们要理解指针到底是什么,我们常说的指针就是指针变量,指针变量既然是一个变量那么就要存放什么东西,指针存放的就其它变量的地址,或者说指针指向的是其它变量的地址。
下面我们来了解一下指针的大小,指针变量的大小与机器本身有关,在32位的机器上,指针的大小为4字节,在64位机器上指针的大小为8字节。
指针还有一个重要的概念,那就是指针类型,我们知道指针指向的是地址,我们如何去用这个地址,或者说是我们按什么方式去访问这个地址,这就要跟据指针类型来决定。
指针类型的第一个含义是:我们在解引用时我们访问多大的字节,例如:int*指针访问时访问4个字节,而char*类型的指针解引用时访问1个字节。
指针类型的第二个含义就是:我们在执行指针运算时每一次向前或向后移动一步的距离。
指针的大小与指针类型无关,只与机器本身有关。
这里我们可以看到我分别定义了一个 int* 跟 char* 类型的指针k和n,通过运算符sizeof计算得到两个不同类型的指针的大小一样都是8字节。(64位机器)。
指针的间接访问操作符:
我们看到当我们想通过指针p来查看a的值时,打印p时打印出来一串看不懂的数字,这个其实就是a的地址是以16进制打印出来的,那么我们如何通过p访问到a的值?这里就用到了间接访问符(*)。
指针存放的地址我们可以通过间接访问操作符来查看地址存放的值是多少,*(间接访问符)这个等于对地址进行解引用。
就是说我知道你家的地址,我就可以通过访问这个地址,来看你家到底有几口人。
我们可以认为解引用操作符(*)跟取地址符(&)他们两个就像是互为反操作,你对一个变量用取地址符就可以得到这个变量的地址,对一个地址用解引用操作法就可以得到这个地址下的变量存放的值。
野指针:
接下来我们了解一下野指针,在了解野指针之前我们先来看看野指针的成因野指针的成因有两种:
第一种是定义时未初始化,
像这样并未对指针k初始化,当你忘记了初始化直接对k指针进行解引用操作,这是不被允许的,你并不知道它指向的是什么。此时就是野指针,所以在定义指针时就要对指针进行初始化,暂时不知道初始化什么时也要将指针指向空指针(NULL)。
第二种就是,数组的越界访问:
像这样数组a只有10个元素,但是通过指针访问到了数组以外的地址,此时指针就会变成野指针。
综上所述我们可以知道野指针就是指向不明地址的指针,就是在说这个指针存的地址并不是我们主动让它存放的,或者说是由于我们的一些不当操作导致指针变成的野指针。
上面两种情况希望大家在写程序时一定要避免出现。
二级指针:
大家看一下这个代码:
Int a=10;
Int* b=&a;
假如说我们现在要定义一个变量c用来存放b的地址c=&b;可以猜想一下这个变量c的类型应该是什么,
我们来分析一下,首先它存放的是地址,所以说他应该是指针,存放的是变量b的地址,b是 int* 类型的指针,所以说c应该是指向 int* 类型的指针,也就是存放指针的指针,声明为(int**),
当我们对c执行解引用操作时*c此时我们根据指针解引用的特点得到的应该是b的值也就是a变量的地址,我们对c执行两次解引用**c此时我们得到的就是a的值,
这张图片当中的代码就是对二级指针的解释。
顺着这个思想我们可以定义三级指针,四级指针等等,当然定义过多的指针的指针只会使程序的可读性变差,最多到二级,一般我们很少用到多级指针。