目录
一、指针的本质(间接访问原理)
1.1.指针的定义
内存区域中的每字节都对应一个编号,这个编号就是“地址”。如果在程序中定义了一个变量,那么在对程序进行编译时,系统就会给这个变量分配内存单元.按变量地址存取变量值的方式称为“直接访问",如printf("%d",i);、scanf("%d",&i);等; 另一种存取变量值的方式称为“间接访问”,即将变量i的地址存放到另一个变量中。在C语言中,指针变量是一种特殊的变量,它用来存放变量地址。
指针变量的定义格式如下:
基类型*指针变量名;
例如:
int *i pointer;
指针与指针变量是两个概念,一个变量的地址称为该变量的“指针”。例如,地址2000是变量i的指针。如果有一个变量专门用来存放另一变量的地址(即指针),那么称它为“ 指针变量"。例如,下图中的i_ pointer就是-一个指针变量:
那么i_pointer本身占多大的内存空间呢?本文中编写的程序都是64位应用程序,寻址范围为64位即8字节,所以对于本文来说sizeof(i_ pointer)=8.。如果编写的程序是32位,那么寻址范围图指针变量就是4字节(考研中往往会强调程序是32位的程序)。
1.2.取地址操作符与取值操作符,指针本质
取地址操作符为&,也称引用,通过该操作符我们可以获取一个变量的地址值;取值操作符为*,也称解引用,通过该操作符我们可以得到一个地址对应的数据。如下例所示,我们通过&i获取整型变量i的地址值,然后对整型指针变量p进行初始化,p中存储的是整型变量i的地址值,所以通*p(printf 函数中的*p)就可以获取整型变量i的值。p中存储的是一个绝对地址值,那为什么取值时会获取4字节大小的空间呢?这是因为p为整型变量指针,每个int型数据占用4字节大小的空间,所以p在解引用时会访问4字节大小的空间,同时以整型值对内存进行解析。
【例】取地址与取值(引用与解引用)
#include <stdio.h>
//&符号是取地址,指针变量的初始化一定 是某个变量取地址
int main(){
int i= 5;
int* p=&i;
printf("i=%d\n",i);//直接访问
printf("*p=%d\n", *p);//间接访问
return 0;
}
读者需要注意以下4点:
(1)指针变量前面的“*”表示该变量为指针型变量。例如:
float *pointer_1;
注意指针变量名是pointer_1,而不是*pointer_1。
(2)在定义指针变量时必须指定其类型。需要注意的是,只有整型变量的地址才能放到指向整型变量的指针变量中。例如,下 面的赋值是错误的:
float a;
int *pointer_1;
pointer_1=&a; //毫 无意义而且会出错,有兴趣的读者可以自行尝试
(3)如果已执行了语句
pointer_ 1=&a;
那么&* pointer_1的含义是什么呢?
“&”和“*”两个运算符的优先级别相同,但要按自右向左的方向结合。因此, &* pointer_1与&a相同,都表示变量a的地址,也就是pointer_1。
*&a的含义是什么呢?
首先进行&a运算,得到a的地址,再进行*运算。*&a 和*pointer_1的作用是一样的,它们都等价于变量a,即*&a 与a等价。
(4) C语言本质上是一种自由形式的语言,这很容易诱使我们把“*”写在靠近类型的一侧,如int*a这个声明与前面一个声明具有相同的意思,而看上去更清晰,a被声明成类型为int*的指针。但是,这并不是一个好习惯,因为类似int *a,b,c 的语句会使人们很自然地认为这条语句把所有三个变量声明为指向整型的指针,但事实上并非如此,“*” 实际上是*a的一部分,只对a标识符起作用,但其余两个变量只是普通的整型变量.要声明三个指针变量,正确的语句如下:
int *a,*b,*c;
二、指针的传递使用场景
2.1.什么是指针的传递
很多初学者不喜欢使用指针,觉得使用指针容易出错,其实这只是因为没有掌握指针的使用场景.经过多年的实战经验总结,指针的使用场景通常只有两个,即传递与偏移,读者应时刻记住只有在这两种场景下使用指针,才能准确地使用指针。多加练习之后,我们会发现指针其实很简单。
2.2.指针的传递使用场景
我们首先来看本例的主函数中,定义了整型变量i,其值初始化为10,然后通过子函数修改整型变量i的值。但是,我们发现执行语句printf("after change i=%d\n" ,i);后,打印的i的值仍为10,子函数change并未改变变量i的值.下面我们通过执行程序来查看为什么会出现这种情况.
【例】指针的传递使用场景:
#inc