前言
在进入指针之前想必大家已经对前面的知识有所掌握,所以在这里我不再对前面的知识进行赘述。指针,它C语言程序设计中最为灵活的一种数据结构,如果说C语言程序设计是一座宝塔,那么指针一定是打开这座宝塔的钥匙。
一、指针是什么?
既然要学习指针、认识指针那么就必须知道指针是什么,请大家务必记住这句话——“指针就是地址,地址就是指针”,当你在指针的汪洋大海里迷航的时候,想想这句话,它总能给你一个方向,提醒你目前所处的位置。
二、如何定义指针?
众所周知,杯子可以用来装水,眼镜盒可以用来装眼镜,脑子可以用来装知识。
虽然我知道可能会有人和我杠,那脑子就不能用来装水嘛?杯子不能用来装眼镜嘛?但是你听我狡辩,我说的是可以,诚如你所言,脑子也可以用来装水,杯子也可以用来装眼镜,但是当这些不搭配的事物组合在一起就显得十分抽象,就好像这么做的这个人指定有什么毛病一样。再看我们的变量,虽然你可以给char类型的变量赋一个整数值,你也可以给int类型变量赋一个字符值,但是这样做意义不明确,本来C语言开发出来就是为了解决人与计算机沟通的问题,而你这么操作显然是在增加难度,除非你所与到的问题非要这么操作,不然你在一个不需要这么做的项目上这么做了,那么你肯定会得到你同事的一句“小可爱”的夸奖。
言归正传,上面我说了不同类型的变量用来存储不同类型的数据,而我们今天的主角——指针也有这一特性,指针也有不同的类型,和定义普通变量一样在定义时,要明确指出该指针变量的类型。同时,int类型的指针变量只能指向int类型的数据结构,char类型的指针只能指向char类型的数据结构......
也许会有人想,既然int类型的变量可以存储char类型的数据,那么int类型的指针变量可不可以指向char类型的数据结构呢?脑回路奇特,但是问的好。我们不妨上代码试试:
根据结果来看,显然这样做是可以的,但是呢,还是那句话,在没有特殊需要的时候不要给自己徒添麻烦搞得太抽象,本来很多人都谈针色变,而在这么继续一整那更加晕针了。
根据上面的例子来看,我们是用了一个指针p指向了一个变量a的地址,那么当我修改了指针p所指向的地址内存的值以后会发生什么呢?我们将程序稍作修改:
根据结果可以看到,当你修改了指针p所指向地址内存放的数据值后,变量a的值也随之发生了改变,由此我们可以得出结论,指针p所指向的地址就是变量a的地址,而我们的数据值,存放在变量中类似于将一段数据存放在容器中,可以想象变量既是容器,而该容器同时具备两个属性,一个是数据类型,一个是看不见摸不着的地址。而我们的指针变量p也具备这样的属性,只是它不能用于直接存储数据,只能间接存储数据,类似于下面的操作:
每个变量在被定义后内存都会为其分配一段内存空间,例如内存会为int类型的变量分配4个字节的存储空间,为char类型的变量分配1个字节的存储空间等等,变量会根据变量的名称和定义类型为其分配相应的空间用来存储数据,完成空间分配的同时内存会给这个变量一个地址,这个地址只能够被指针变量引用,用上图来讲就是指针变量p指向了变量a的地址2001,将这个2001作为指针值存在指针p内,例如我们以八进制方式就可以输出上面例子中指针变量p的值了:
根据结果可以看到,在声明初期指针p的值为八进制的20,变量a的地址为30377024,当我们把变量a的地址赋给指针p以后,指针p的值也指向了变量a的地址。因此我们便证明了指针变量内存放的是地址,如果直接对指针变量进行赋值操作,那么只能给其赋地址类型的值。
而地址这一类型的值在C语言中,比比皆是。这里为大家列举一些今后要遇到的:
指针使用范围不完全统计对照表 | |||||
数据结构 | 地址引用 | 指向 | 数据结构 | 地址引用 | 指向 |
变量 | 指针变量 = &变量名 | 变量地址 | 数组 | 指针变量 = 数组名 | 数组首元素地址 |
数据结构 | 地址引用 | 指向 | 数据结构 | 地址引用 | 指向 |
数组元素 | 指针变量 = &数组名[下标值] | 数组元素地址 | 字符串 | 指针变量名=“字符串” | 字符串首元素地址 |
数据结构 | 地址引用 | 指向 | 数据结构 | 地址引用 | 指向 |
函数 | 类型 (*指针变量名) (形参列表) | 函数地址 | 多维数组 | 指针变量 = 多维数组名 | 多维数组首元素的地址(就是首行的地址) |
数据结构 | 地址引用 | 指向 | 数据结构 | 地址引用 | 指向 |
指针变量 | 类型 **指针变量a = 指针变量b | 指针变量b所指向的地址 | 结构体 | Struct 结构体名 *指针变量名 | 该结构体内的某个元素的地址 |
数据结构 | 地址引用 | 指向 | 数据结构 | 地址引用 | 指向 |
链表 | Struct 结构体名a *指针变量名a = 结构体名b | 下一个结构体的起始地址 | 文件 | FILE *指针变量名 | 内存中的文件信息区的开头 |