首页 /  技术专区  /  C 屏幕太窄?试试伸展一下吧 >

指针概述

1、指针

1.1 指针与指针变量

1.1.1 指针

前面说过,指针就是地址,指针和地址是同义词。

1.1.2 指针变量

存放指针的变量就是“指针变量”。

1.2 *与&

1.2.1 & 

(1)&作为双目运算符使用时,为“位与”运算符

int a = 0x10;
int b = 0x04;

int c = a & b;

(2)&作为单目运算符使用时,为取地址运算符

1)取变量的地址

int a = 100;

&a代表的是a变量第一个字节的地址,也即是a的指针。

2)取函数的地址

int fun()
{

}

&fun即函数的指针,也即函数代码所在空间第一个字节的地址,只不过为了方便使用,往往将&省略,也就是说函数名可以直接代表函数的指针。

也就是说fun与&fun等价。

3)取数组的地址

int buf[7] = {0};

&buf为整个数组的地址,注意是整个数组的地址,不是数组第一个元素buf[0]的第一个字节的地址(指针),&buf[0]和buf才是,与数组指针相关的内容,我们留到讲数组时再介绍。

1.2.2 *

*作为双目运算符时是乘号,作为单目运算符时则与指针有关。

(1)用于组建指针类型

*与int/float/struct Student等类型相结合,构成指针类型。

int a = 100;
int *p = &a;

此时p和a是两个不同的变量,各自拥有自己独立的变量空间。

a:是整形变量,用于存放整形数100

p:是指针变量,用于存放整形变量a的指针。

由于p中存放了a的指针,所以我们说p也指向了a,但是我们前面说过,本质是p里面放的指针指向a。

什么叫“指向”?

答:指向的意思就是,可以通过这个地址找到对应的空间,并访问它。


(2)解引用时

int a = 100;
int *p = &a; 

*p = 200;  //*p:解引用

此时整个*p代表就是p中指针所指向的空间,也就是a的空间,所以*p=200与a=200的效果是一样的。

此时*的作用就是解引用,解引用时*p是一个整体。

这里还要注意的是,使用*解引用时,其实解引用的是p中的指针,而不是p本身,p只是装指针的容器。

总结解引用的目的:找到指针所指向空间,找到后我们就可以访问(读写)它了

读:从空间读数据

int a = 100;
int *p = &a; 

int c = *p; //从*p所代表的空间中读数据

写:修改空间数据

int a = 100;
int *p = &a; 

*p = 200; //往*p所代表的空间中写数据


1.2.3 在c程序中,获取存储空间地址(指针)方式有哪些

(1)直接获取数字形式的地址

int *p = (int *)0x4234f5e4;
*p = 200; //向0x4234f5e4所指向的空间,写入200

像这种方式有个前提,那就是程序员需要事先知道这个地址所对应的空间是可用的,可用的意思是?

1)地址对应的空间存在

2)这个空间没有被别人(变量、常量、代码)使用

3)空间的访问权限,能够满足我们的访问要求


在纯应用的c程序中,我们是不知道具体哪个地址是可用的,我们只能采用&a等方式来使用,编译器在编译时,会将它变为具体的地址值,程序员不需要具体的地址值。

疑问:什么时候会直接使用数字形式的地址呢?

答:这个一般在单片机、驱动等偏硬件的c程序中才会用到,因为开发偏底层的程序时,往往会直接通过数字形式的地址来访问存储空间,为什么会这样呢?

其实只要你学习过单片机和驱动,你很容易就能理解我所说的,否则就算我解释了你不太明白,所以目前大家只需要知道存在这种情况即可。

我们目前讲的各种c例子程序,都是属于应用的c程序,与底层硬件无直接关系,所以我们不会用到纯粹数字形式的地址。

疑问:进行单片机、驱动开发时,我怎么知道具体那个数字地址可用?

答:我们需要产看硬件的说明手册。

(2)使用&

int a;
int *p = &a;
*p = 200;

作为程序员的我们,其实并不知道a的指针具体是多少,所以无法直接使用数字形式的地址,所以只能使用&a方式来代表,编译器会把它变为具体的地址。

这里一定要注意,a不是指针,a只是一个的符号,&a才是a的指针。

(3)malloc返回地址

int *p = malloc(4);

malloc从堆中开辟空间后,程序员也不需要知道这个空间的指针(第一个字节的地址)是多少,也没法知道,因为malloc在运行的过程时才会到堆中开辟空间,到那个时候才知道。

所有只能是在运行的过程中,让malloc将地址(指针)返回并放在p中,然后通过p去间接的使用指针。

(4)某些符号本身就是地址(指针)

1)例子1

char *p = "hello wolrd,it is butefull";

"hello wolrd,it is butefull"是一个字符串常量,它放在了.rodata中,而p中放的是"hello wolrd,it is butefull"所在常量空间的指针。

千万不要以为字符串存放在了p中,p只有4或8个字节,这个字符串存放时需要十几个字节,不可能将字符串放到p中的,所以p中只能放字符串的指针,然后通过这个指针去访问常量空间中的字符换。

对于程序员来说,我们并知道字符串所在常量空间的指针是多少,所以在c语法中,此时整个字符串"hello wolrd,it is butefull"就直接代表那个指针。

疑问:char buf[] = {"hello wolrd"},这种情况也是的吗?

答:这种情况不是的,此时字符串字节放在了数组中,所以这里的"hello wolrd"不代表指针。

2)例子2

int fun()
{

}

fun这个符号就是函数的指针,即函数代码所在空间的第一个字节的地址。


1.2.4 解引用时,指针的使用方式有哪些

两种,一种是直接使用,另一种是间接使用。

(1)直接使用

直接对指针进行解引用,这就是直接使用。

1)例子1

*((int *)0x43355435) = 100;

2)例子2

int a;
*(&a) = 200;

(2)间接使用 

先放到指针变量中,然后通过指针变量去使用。

int a = 10; 
int *p = &a;

*p = 200;

这种间接的使用方式,才是我们最常见的方式。

这里一定要注意,指针变量只是一个放指针的“篮子”而已,真正起作用的是里面所放的指针。

1.2.5 *和&互为逆向运算符

int a = 100;
int *p = &a;

*p = 200;

由于p中放的是&a,而解引用的是p里面的指针,所以*p = 200实际上就等价于*&a = 200;

*&a的意思就是,找到&a这个指针所对应的空间,其实就是a的空间,因此*&a = 200等价于a=200。

其实相当于*和&相互抵消了,因为这两个能相互抵消,所以*和&互为逆向运算符,就好比+-、*/互为逆向运算一样。



0/200
图片验证码