相信我,指针绝对比你想象中的简单100倍,仅仅只是因为人云亦云说指针抽象难以理解。实则不然,放好心态去学习即可。
指针介绍:
首先明确指针是一种数据类型(分为int型指针,char型指针等等),除了本身的数据外,还定义一系列的操作。
关于对“指针是一种数据类型”的理解可以类比int 数据类型,本身代表一个整型数据,并定义了'+','-','*','/'等相关操作。
那么问题来了,指针中的数据到底是什么???
答:是指针所指向的目标数据的内存地址~看这个简视图(自己手画有点丑...)
![d564e54d3607473df81bc05e7caad2be.png](https://i-blog.csdnimg.cn/blog_migrate/6c9defef39fee5f348252fe1f33c3847.jpeg)
例如:
int
首先这里整型a中的数据为5,这里假设整型a的内存地址为1024,那么int型指针p中的数据也就是1024。这里引入一个关键的概念,指针的类型与指针所指向的数据类型,这是理解指针的重中之重。在这个例子中指针的类型为int型指针,指向的数据是int型数据。
强烈建议试试下段代码,对理解指针有着相当大的作用:
int
其中%p指的是内存地址类型(打印出的是16进制数据)
③打印的数据是什么?你们先自己思考 后面会讲到。
指针的相关操作(运算)
算数运算(‘+’&&‘-’)
首先明确千万不要跟int型数据的‘+’法搞混。指针的运算具体来讲是这样的,假设指针p指向的数据类型是Datatype,即这里p是一个Datatype类型的指针。指针的加减法实际上称作“位移”更为合适。例如p+1指的就是将指针p位移一个sizeof(Datetype)单位,即指针p指向了位移后的内存地址。所以参于指针的运算不能是两个指针。
举个简单的例子:
int
观察输出的值很容易的发现一个规律就是,p+1指针的指向从a[0]跳到了a[1],同理可以改变上述程序的一些参数,并且试着定义其他数据类型的数组,这里强烈建议尝试定义结构数组,并进行访问。
间接访问运算(‘*’)
简单明确的理解就是“访问指针所指向数据的值”,注意与“指针的值”和“指针的地址”相互区分,搞懂这个概念,你对指针就有了一个更清晰的理解。
这里用举一个结构指针的例子;
struct
注:(*p).data可以替换为p->data
指针的指针&&在二维数组中的延伸
指针的指针
顾名思义,即指向指针这个数据类型的指针,还记得上面那个输出③吗,输出的值就是指针p的地址,那么这个时候我们完全可以再定义一个指针变量,存储该地址,指向指针的指针就应运而生了。
int
在二维数组中的延伸
前面我们应该已经知道在一维数组中a中,a表示一个指针,指向的数组a中的首元素。
那么在二维数组中不过是对这个概念进行了扩充,例如a[5][4],这里的a本质上是一个数组指针指向一个容量为5的一维数组而已。a[0],a[1]等如同一维数组中a一样指向他们所对应的一维数组中首个量。
自己动手试试下面的实验,帮助理解数组,指针之间的关联。
#include
数组指针vs指针数组
数组指针
数组两个字放在前面表示什么?没错,表示的是指针指向的数据类型。
例如: int * [5] p ,定义一个指向容量为5的一维数组的指针p。事实上类比二维数组,这个指针p指向的是一个指向某个容量为5的一维数组第一个数据的指针。
指针随着指针类型的变化,它的运算方式‘+’也发生了改变。(这里有一个问题,由于博主未接触过指针的更底层的源码,我的猜想是这样的:为了分辨指针的类型,指针的属性中可能还有一些参数,用于辨别指针位移的大小,如同二维数组中a[][]的指针a,本身实际上是一个指向整型指针的指针,但对a做‘+’运算时位移的单位却不是一个sizeof(int),所以推断a一定还有其他参数制约了该操作)
指针数组
字符数组是什么?存储字符的数组。那么指针数组是什么,存储指针的数组!
没问题,聪明的前辈们想到用数组存储一连串的指针,最常见的用法就是在定义多个字符串的时候。
例:#
在上列中定义了指针数组p,并定义了指向指针的指针pp。
这里结合上述的二级指针(指针的指针)给出适当的例子予以解释
#include
这里注意的问题是,试图访问字符串时,直接用指向字符串的指针即可,不用使用*进行间接访问。
#include
最后这里留有一道题目:尝试用指针数组实现多个字符串的动态输入
指针与函数:
指针作为函数的参数
在c语言中,不同于c++,并无引用传递,而只能进行进行值传递。若需要调用函数来修改某些量时,就需要用到指针。通过将地址当做实参传给函数中形参(即指针),完成赋值。
举例冒泡排序法
#include
指针作为函数的返回值
函数的返回值可以是int,可以是char,当然也可以返回一个指针类型(一开始已经说过了指针属于一种数据类型)。
下面例子就是一个简单返回指针的例子,实际上就是传递一种数据类型,不过这种数据类型特殊点,叫做指针,并且他的数据是另一个数据的地址。
例:输入一个字符串和一个字符,如果该字符在字符串中,就从该字符首次出现的位置开始输出字符串中的数字(最后可以直接用指针打印出来字符串,末尾有’/0‘判断)
#include
指向函数的指针
在c语言中,函数名代表函数的入口地址。可以定义一个指针变量,并接受函数的入口地址让它指向函数,这就是指向函数的指针,也称为函数指针。通过函数指针可以调用函数,它还可以作为函数的参数。
1.函数指针的定义
类型名*(函数名)(返回值类型)
int *(funptr)(int,int)
定义了一个函数指针funptr,它可以指向有两个整型参数且返回值类型为int的函数。
2.通过函数指针调用函数
使用前函数指针前,需要先对函数指针进行赋值,将一个函数名赋给函数指针,但该函数必须已定义或者已声明,且函数返回值类型与函数指针的类型要一致。
3.函数指针作为函数参数
c语言中,利用函数名作为实参,函数指针作为形参,完成传递传递函数。
例:利用函数指针实现
#include
(未完待续)