一、关于指针的几个概念:
1.指针就是地址
2.获取任何变量的地址都是:&变量名(&是取地址运算符)
3.*指针变量名,则间接访问到指针所指向的变量(*是间接访问符,又名解引用)
4.指针类型相同才能赋值
通过代码可以仔细了解:
#include <stdio.h>
int main()
{
int a = 10;
int b = 20;
int *p = &a; //定义时*说明p是个指针(地址)变量
*p = 100; //解引用p,此处可理解为a = 100;
p = &b; //将b的地址赋值给指针变量
*p = 200; //再次解引用p,此处可理解为b=200;
int **pp = &p; //定义时**说明p是个存放指针(地址)变量的指针变量,即二级指针
//int a,&a->int*,int *p,&p->int **
*pp = &a; //对二级指针解引用一次变成了一级指针,此处可理解为p=&a;
**pp = 1000; //对二级指针解引用两次变成了变量,此处可理解为*p = 1000;a=1000;
*pp = &b; //将b的地址赋值给解引用一次的二级指针,p = &b;
**pp = 2000; //在次对二级指针解引用两次,此处可理解为*p = 2000;b =2000;
int *q;
pp = &q;//将一级指针的地址赋值给二级指针
//pp = &a;//error//将变量的地址赋值给二级指针
char c = 'C';
char *cp = &c;//ok//字符型指针变量存字符型数据地址
//p = &c;//error//将字符型数据地址给了整形指针
double d = 12.5;
double *dp = &d;//ok
//p = &d;//error//将浮点型数据地址给了整形指针
return 0;
}
可以发现指针变量的使用比其他变量多了一个解引用。引用符号*,(如:*变量名=100;)就是一个解引用过程。
二、指针的大小
既然各类型的变量大小都不相同,那么各类型的指针大小相同吗?大小又是多少呢?
我们使用sizeof(变量)计算。
#include <stdio.h>
int main()
{
printf("%d\n",sizeof(char*));
printf("%d\n",sizeof(short*));
printf("%d\n",sizeof(int*));
printf("%d\n",sizeof(long*));
printf("%d\n",sizeof(long long*));
printf("%d\n",sizeof(float*));
printf("%d\n",sizeof(double*));
printf("%d\n",sizeof(double**));
printf("%d\n",sizeof(double**********));
return 0;
}
可以发现结果都相同,即
在x86或者32位平台,指针4字节
在x64或者64位平台,指针8字节
三、指针的使用
首先引入两个概念。子函数:被调用函数 ;父函数:调用函数。
指针的使用最主要的地方就是子函数的改变修改父函数的值,而要实现就必须有:1)传指针;2)解引用。
但是使用仍然容易进入误区,在下面的的代码讨论:
//未传指针,未解引用;子函数与父函数a,b地址不同
void Swap_err1(int a,int b)
{
int tmp;
tmp = a;
a = b;
b = tmp;
//printf("%d,%d\n",a,b);
}
//有传指针,但是没有解引用;
//p1开始指向a的地址,之后指向b的地址
//p2开始指向b的地址,之后指向a的地址,但对父函数无影响
void Swap_err2(int *p1,int *p2)
{
int *tmp = p1;
p1 = p2;
p2 = tmp;
}
//引入了野指针(即悬挂指针),使程序无法正常进行。
void Swap_err3(int *p1,int *p2)
{
//int *tmp;//野指针,悬挂指针
//*tmp = *p1;
//*p1 = *p2;
//*p2 = *tmp;
}
//传指针+解引用
//p1存放a的地址,变量a存放的数据被放到b
//p3存放b的地址,变量b存放的数据被放到a
void Swap(int *p1,int *p2)
{
int tmp= *p1;
*p1 = *p2;
*p2 = tmp;
}
int main()
{
int a = 10;
int b = 20;
Swap(&a,&b);//被调用函数,子函数
printf("%d,%d\n",a,b);
return 0;
}