指针
廖家龙 用心听,不照做

变量的值:存储在变量中的数据叫做变量的值
变量的地址:一个变量是由一个或多个字节组成的,组成这个变量的低字节的地址,就是这个变量的地址

变量的地址就叫做指针,指针变量就是专门用来存储地址的变量,专门用来存储另外一个变量的地址,那么我们就说这个指针变量指向了另外一个变量【它自己也有一个地址】,通过指针变量可以间接的访问指针变量指向的另外一个变量

int* p1;,代表声明了一个叫做p1的指针变量,这个指针变量的类型是int,这个代表这个变量不是一个普通变量,而是一个专门用来存储地址的指针变量【只能存储int变量的地址】

指针变量初始化只能给他一个地址:int* p1=#

使用指针间接的操作指向的变量:

1
2
3
4
int num = 10;
int* p1=#
*p1=100; //*p1代表指向的变量,也就是num

运算符&:获得变量的地址,它的操作数必须是变量:int i;printf(“%p”,&i);

*是一个单目运算符,用来访问指针的值所表示的地址上的变量,可以做右值也可以做左值
int k=*p;
*p=k+1;

指针的一些注意点:

1)【指针+1】并不是在指针地址的基础之上加一个字节的地址,而是在这个指针地址的基础之上加一个单位变量占用的字节数【这个时候p1指向的就是num1】

2)p++的意思是取出p所指的那个数据,之后再把p移到下一个位置去,的优先级虽然高,但是没有++高,常用于数组类的连续空间操作

3)int* p1;
我们声明一个指针变量,如果没有为其初始化,那么这个时候这个指针变量是有值的,这个值是一个垃圾值,,这个时候,这个指针变量就有可能指向了一块随机的空间,像这样的指针我们就叫做野指针【最好给他初始化一下:int *p1=NULL;NULL值代表指针变量不指向内存中的任何地址】

4)多个指针指向同一变量:

5)指针分好多类型,但无论指针什么类型,在内存中都是占据着8个字节,指向不同类型的指针是不能直接互相赋值的,这是为了避免用错指针

6)p1指针变量中存储的是num变量的地址,也就是num变量的低字节的地址,这个时候p1指针能操作多少个字节是根据指针的类型来决定的【这就是为什么指针要分类型,还必须跟指向的普通变量的类型一致】

一级指针和多级指针:

一个指针变量中存储的是一个普通变量的地址,像这样的指针,我们就叫做一级指针
一个指针变量中存储的是一个一级指针变量的地址,像这样的指针,我们就叫做二级指针

声明多级指针:

一级指针只能存储普通变量的地址,二级指针只能存储一级指针变量的地址

指针与数组:

使用指针来遍历数组:
1)

2)本方法中不能换成*(arr++),数组名代表数组的地址,而数组一旦创建,数组的地址就确定了,不能改变,所以我们不能为数组名赋值,不能修改数组名的值,但是可以使用数组名的值

3)此方法跟前两种不一样

中括弧的本质【数组arr[0]等价于*(arr+0),操作数组我们虽然使用中括弧下标来操作,实际上内部仍然是使用指针来操作】:
指针变量后面可以使用中括弧,在中括弧中写上下标来访问数据:p1[n]完全等价于*(p1+n)

函数参数表中的数组实际上是指针,但是可以用数组的运算符[]进行运算

数组变量是特殊的指针:
1)数组变量本身表达地址,所以int a[10];int *p=a;无需用&取地址,但是数组的单元表达的是变量,需要用&取地址
2)[]运算符可以对数组做,也可以对指针做
3)*运算符可以对指针做,也可以对数组做
4)数组变量是const的指针,所以不能被赋值:int a[];int * const a;

如果一个数组是用来存储指针类型的数据的话,那么这个数组就叫做存储指针的数组:int* arr[3];


指针之间的运算:指针与指针之间只能做减法运算,不能做加乘除运算,可以做比较运算

指针与指针之间可以做减法运算,结果是一个long类型的数据,代表两个指针指向的变量之间相差多少个单位变量

如果参与减法运算的两个指针不指向同一个数组,先求出两个指针的差/每一个指针变量对应的普通变量占用的字节数

指针的比较运算:

指向函数的指针:
程序在运行的时候,会将程序加载到内存,程序中的函数肯定存在于内存的代码段中,我们可以声明一个指针,存储这个函数的地址,让这个指针指向这个函数,使用指针来间接的调用函数

一个指向函数的指针,并不是任意的函数都可以指向,要求指向的函数的返回值类型和参数类型必须要与指针的描述一样

函数的名称就代表这个函数的地址:【注意不要在函数名后加小括弧,如果加了小括弧,就代表指向这个函数,拿到这个函数的返回值】

如果指向的函数有参数有返回值,调用的时候有参数就传参,有返回值就接!