一、指针
1.1 指针的本质
1.1.1 指针的定义
内存区域中的每字节对应一个编号,这个编号就是“地址”。如果在程序中定义了一个变量,那么在对程序进行编译时,系统就会给这个变量分配内存单元。按变量地址存取变量值的方式称为“直接访问”;另一种存取变量值的方式成为“间接访问”,即将变量i的地址存放到另一个变量中。C语言中,指针变量是一种特殊的变量,它用来存放变量地址。
指针变量的定义格式:
基类型 *指针变量名;
指针与指针变量是两个概念,一个变量的地址称为该变量的“指针”。如下图,地址2000是变量i的指针。如果有一个变量专门用来存放另一变量的地址(即指针),那么称它为“指针变量”。例如下图中的i_pointer就是一个指针变量。

1.1.2 取地址操作符与取值操作符
取地址操作符为&,也称引用,通过该操作符我们可以获取一个变量的地址值;取值操作符为*,也称解引用,通过该操作符我们可以得到一个地址对应的数据,如下图所示。

注意以下3点:
- 指针变量前面的“*”表示该变量为指针型变量。如下:
float *pointer_1;
注意:指针变量名是pointer_1,而不是*pointer_1。
- 在定义指针变量时,必须指定其类型。需要注意的是,只有整型变量的地址才能放到指向整型变量的指针变量中。例如以下的赋值就是错误的。
float a;
int *pointer_1;
pointer_1 = &a; //毫无意义而且会出现错误
- 如果已执行了语句
pointer_1 = &a;
那么&* pointer_1的含义是什么呢?
“&”和“*”两个运算符的优先级相同,但是要自右向左的方向结合。因此&*pointer_1与&a相同,都表示变量a的地址,也就是pointer_1。
*&a的含义是什么呢?
首先进行&a运算,得到a的地址,在进行*运算。*&a和*pointer_1的作用一样的,他们都等价于变量a,即*&a与a等价。
1.2 指针的使用场景
指针的使用场景只有两个:即传递和偏移。
1.2.1 指针的传递

原理图如下图所示。程序的执行过程,我们需要关注的是栈空间的变化。当main函数开始执行时,系统会为main函数开辟函数空间,当程序走到int i时,main函数的栈空间就会为变量i分配4字节大小的空间。调用change函数时,系统会为change函数重新分配新的函数栈空间,并为形参变量j分配4字节大小的空间。在嗲用change(i)时,实际上是将i的值赋值给j,我们把这种效果成为值传递(C语言的函数调用均为值传递)。因此,当我们在change函数的函数栈空间内修改变量j的值后,change函数执行结束,其栈空间就会释放,j就不再存在,i的值不会改变。

问题:难道就不能在子函数中修改main函数内的某个变量的值?答案是可以的,修改程序如下:
#include<stdio.h>
//C语言形参的位置不能出现&,因为C语言不支持引用
void change(int *j) //j叫形参
{
*j = 5; //间接访问
}
//指针的传递使用场景
int main()
{
int i = 10;
printf("before change i=%d\n", i);
change(&i);//i叫实参,实参赋值给形参的过程,实参可以是变量,可以是表达式
printf("after change i=%d\n", i);
return 0;
}
在程序执行后,打印的i的值为5,难道C语言函数调用值传递的原理变了?并非如此,我们将变量i的地址0x0099FC38传递给change函数时,实际效果是j=&i,依然是值传递,只是这时我们的j是一个指针变量,内部存储的是变量i的地址,所以通过*j就间接访问到了与变量i相同的区域,通过*j=5就实现了对变量i的值的改变。如下图所示,我们依然可以看到变量j自身的地址是0x0099FB64,它与变量i的地址不相等。

5427

被折叠的 条评论
为什么被折叠?



