C语言的指针
指针的含义
计算机在储存数据时,会把数据放到内存里的某个位置,每个位置都对应一个地址,使用这些数据时,也是从对应的地址里拿取数据来使用。而在C语言中,我们把这些地址称为指针。
打个比方:指针(地址)就像是宿舍楼的房号,只要知道某个同学住的房间的房间号,社管就可以通过查找房间号来找到这个同学。
指针变量的表示
在C语言中,我们常用这样的方式来表示(创建一个指针变量): (type of date)* name
也就是--被指向的对象的类型+*+指针变量的名字
取地址操作、指针变量的初始化和解引用操作
取地址操作
取地址操作用取地址操作符&
来完成.
这里我们用&符号把a的地址打印出来,对比调试--->内存中的值,我们发现两者是相同的,&a成功地把a的地址拿出来了
指针变量的初始化
我们说,指针变量是用来储存地址的变量.现在我们已经学会了用&
拿到地址,那么我们就可以给指针变量初始化了.初始化的格式如下:
指针变量的类型
+指针名
=&变量名
;
例如:初始化一个int*类型的指针,指针名为p,p中存放了变量a的地址(a是int类型的变量):
int a=123; int* p=&a;
注意:指针变量的类型一定要和它指向的变量的类型相对应!
解引用操作
我们已经会把变量的地址存放到指针变量里了,那么我们要怎么通过指针变量来找到它指向的数据(变量)呢?对指针变量进行解引用操作.
解引用操作通过解引用操作符*
来实现.
例如,我们想拿到p指向的数据并赋值给变量b,我们可以这样写:
int b=*p;
指针的分类
由指向的对象的类型来分可以分为:
整形指针(int*
);
浮点数指针(float*
);
数组指针(指向数组);
函数指针(指向函数);
void*指针;
......
这类分类方法就能分出很多类了,毕竟有啥类型的数据就有啥类型的指针变量.
上面的指针我们统称为一级指针,除此之外,还有二级指针(指向一级指针)、三级指针(指向二级指针)等,想必读者也能猜到,按这么套娃下去,可以有无限级的指针,事实确实如此.尽管高级的指针非常强大,但因为指针的逻辑比较复杂,没高一级指针,逻辑的复杂程度都会高很多,所以我们常用的只有一级指针和二级指针,三级指针用得比较少,三级以后就更少了.
指针变量类型的意义和指针运算
指针类型的意义
有了不同类型的指针,我们就可以创建不同类型的指针变量.不同的指针变量的意义和作用是不同的,尤其体现在指针运算中.
之前说过,计算机通过地址来访问数据.但是不同类型的数据占据内存的大小是不一样的,因此,我们在使用指针的时候,必须告诉计算机这是什么类型的数据,以便于它能够正确的访问数据.下面给出两个例子:
例如:int*
类型的指针解引用访问4个字节,char*
解引用访问1个字节.
int main() { int a = 0x11223344; int* p = &a; *p = 0; return 0; }
用a的地址给p初始化之后,p就指向了a变量的地址,地址中存放有数值0x11223344,占了内存中的四个字节(为什么在调试时显示为44 33 22 11此处不做解释,感兴趣的读者可以移步学习整形在内存中的储存和大小端字节序的相关内容).
当运行完*p=0;
时,可以看到,p指向的位置,四个字节全部变成了0,说明对*p的操作,操作了4个字节的内容.
下面我们把p改成char*
类型的指针变量试试
int main() { int a = 0x11223344; char* p = (char*)&a; *p = 0; return 0; }
可以看到,这次运行完*p=0
之后,只有一个字节的内容被改为了0,说明*p只能操作一个字节的内容.
void*类型的指针
void*类型的指针可以指向任何类型的变量,因此编译器并不知道要访问几个字节的内容,无法对其进行解引用操作
指针运算
指针的运算分为三种:+ - 和指针与指针的运算
+和-
+和-
运算与指针变量的类型有关,int*类型的指针变量+1或-1跳过4个字节(当然,+1是向高地址跳,-1是向低地址跳),char*类型的指针变量+1或-1跳过1个字节,void*类型的指针变量不支持+-操作
指针与指针的运算
指针和指针之间也支持加减运算和逻辑运算,例如:
int a=0; int b=0; int* p_a=&a; int* p_b=&b; printf("%d",p_a-p_b); if(p_a-p_b>0) printf("p_a是高地址"); else printf("p_a是低地址"); #a和b是两个不同的变量,两者地址不会相同
完.