1、指针的概念
C程序中变量的值都是存储在计算机内存特定的储存单元中的,内存中的每个单元都有唯一的的地址,就像街区中的房子都有唯一的地址、宾馆中的房间都有唯一的编号一样。那么如何获取这个地址呢?这就要用到取地址运算符,即“&”。计算机把整个内存条分成一个个的小小的存储单元,每个存储单元都有一个唯一的地址。
定义:
类型关键字 *指针变量名 = &变量名;
内存中的地址都是按字节编号的,即内存中每个字节的存储单元都有一个唯一的地址,在程序编译或函数调用时,根据程序中定义的变量类型为变量分配相应字节数的存储空间。如图1.1所示。在内存中定义了一个变量i,再将i赋值为5,即i的内容中保存了一个5,对于这个内存位置在内存条中有一个唯一的编号去标志这一块内存区域,即地址0x0012 FF00。当定义了一个指针类型的变量时pi时,在内存条中也会去分配给它一个唯一的地址,在pi的内存区域中也存放了一个地址,这个地址就是变量i的地址。所以我们可以根据pi中存放的地址去寻找变量i的内容
图1.1
与图1.2所示,简单来说就是pi指向i的内存空间,i的内存空间存放的内容是5,pi的内存空间存放的是i的地址。
图1.2
2、指针访问
2.1、直接访问
当我们想使用指针时,我们可以直接利用变量的地址进行存储,在变量前加一个“&”,即取地址运算符。
例如:
1> scanf("%d",&num);
首先找到变量num的起始地址,比如起始地址为10010;然后将键盘输入的值,比如3保存到10010开始的位置。此时,变量num在内存中的地址和值就为10010和3。
2> printf("num = %d\n",num);
首先找到变量num的起始地址10010,然后在10010开始的四个字节中取出值3,最后再将它输出。
2.2、间接访问
间接访问是我们使用较多的一种方式,其访问方式就是通过指针取访问某一个变量的值。其指针就是存放其他变量的地址的一种特殊的变量。
例如:
int x = 10;
int *y = &x;
通过指针变量y存取变量x的值的过程如下:
首先找到指针变量y的地址,例如11001,读取y中保存的值,例如10010,(10010为变量x的地址);然后再从10010的起始位置读取四个字节的内容(10)。图解表达如图2.1所示
图2.1
程序示例:
#include "stdio.h"
int main()
{
int x = 10;
int *y = &x;
printf("&x = %p\n",&x);
printf("y = %p\n",y);
return 0;
}
运行结果为:
&x = 000000000061FE14
y = 000000000061FE14
由此可以说明,y里面存储的是x的地址,也表明刚刚的图解是正确的。
3、指针变量和指针
3.1、指针变量和指针
- 一个变量,保存的是另一个变量的地址的叫做指针变量。
- 一个变量的地址称为该变量的“指针”。
- 解析:地址1010110是变量x的地址(指针),指针变量p来存放x变量的地址,则p为指针变量,x的地址1010110称为指针。
用图可以表示为:
其中p为指针变量,保存的是x的地址1010110,x的地址1010110为指针,x为一个普通变量。
3.2、“&”和“*”的使用
当我们定义了一个变量x,即int x = 10;我们要定义一个指针指向x时,就写为int *y = &x;现在y中存的就是变量x的一个地址。当我们想要修改x的值时,我们可以直接在y的前面加一个*,即*y = 20,这样我们就可以通过指针去修改x的一个值,即*y等价于x。全部过程即为:
int x = 10;
int *y = &x;
*y = 20;
3.3、野指针
有如下代码,请问有什么问题?
#include "stdio.h"
int main()
{
int x,*pi;
*pi = 5;
printf("%d,%d\n",x,*pi);
return 0;
}
当我们运行这个代码时,编译器可能会在第七行进行报错。这是因为指针变量pi和变量x都没有初始化。因此指针变量pi的值在此处通常不可预知。语句*pi = 5;执行时将向一个位置不可预知的存储单元写入数据,这样的操作可能导致非法内存访问错误或者程序逻辑上的错误。右值为不属于程序所拥有存储单元的地址的指针变量称为“野指针”。
4、指针案例
通过一个函数去交换两个变量的值。
#include "stdio.h"
void fun(int x,int y)
{
int temp;
temp = x;
x = y;
y = temp;
printf("x = %d, y = %d\n",x,y);
}
int main()
{
int x = 123;
int y = 234;
fun(x,y);
printf("X_ = %d, Y_ = %d\n",x,y);
return 0;
}
运行结果为:
x = 234, y = 123
X_ = 123, Y_ = 234
可以看到,因为x和y是一个形参,对于形参是实参的一个拷贝,所以只在fun()函数中对拷贝本进行了交换,但是不影响我们的一个变换,即这种方法是不可改变的。
该例我们传进去的是一个指针变量(地址),即int *x,int *y。这样我们在函数中对其进行了交换。
#include "stdio.h"
void fun(int *x,int *y)
{
int temp;
temp = *x;
*x = *y;
*y = temp;
printf("x = %d, y = %d\n",*x,*y);
}
int main()
{
int x = 123;
int y = 234;
printf("X_init = %d, Y_init = %d\n",x,y);
fun(&x,&y);
printf("X_ = %d, Y_ = %d\n",x,y);
return 0;
}
运行结果为:
X_init = 123, Y_init = 234
x = 234, y = 123
X_ = 234, Y_ = 123
可以看到,x和y原来的值是123和234,运行fun()函数之后,x和y的值进行了改变,即x和y的值就变为234和123。