一.指针的定义——操作数据的地址
1.地址
计算机中所有数据都是存储在内存中,内存是以字节为单位的连续编址空间,每一个字节对应一个独一的编号,这个编号被称为内存单元的地址,即某个变量的地址。
2.基本符号
&——获取地址
int* x=&m或int *x=&m——令x指向m的地址即x=&m
*x——即获得地址为x的存储m
3.定义
int* p=&n或int *p=&n定义指针变量p,p值为变量n所在的地址,*p则指向p值地址上的变量n,即*p=n。
野指针:int* p这样定义没有任何指向的指针成为野指针,这样的指针会随机指向某个变量或值,可能导致无法运行,危害很大。改正为int* p=null可以使指针指向空而不会影响程序的运行。
二.指针的应用
例子:交换变量
int main(void){
int a=1,b=2;
swap(&a,&b);//将a,b两个地址上的值交换
printf("%d,%d",a,b);
}
void swap(int *pa,int *pb){
int t=*pa;
int *pa=*pb;//改变地址为&a上的值为b
int *pb=t;//改变地址为&b上的值为a
}
这样输出a=2,b=1达到交换变量的效果
如果写成下面这样
int main(void){
int a=1,b=2;
swap(a,b);
printf("%d,%d",a,b);
}
void swap(int pa,int pb){
int t=pa;
int pa=pb;
int pb=t;
}
输出结果为a=1,b=2
这是因为不用指针时,只是将值赋值给pa和pb,让pa与pb的值交换,而主函数中的a,b的值却不会受到影响,而如果使用指针则是直接修改地址&a,&b上的值也就是a,b的值达到交换的效果
三.指针的运算
1.指针的赋值
由于指针保存的信息为数据与地址两种,所以不能直接给指针赋值,错误:int* p=100;而是要先将数字转换为指针类型才能进行赋值,正确:int* p=(int*)100。(与char a=(char)100类似)
2.指针的加减
指针加减n时,指针指向的首地址会向前或先后移动(n*步长)个字节,例如:
int *a=(int*)100;//int类型每个数据字节为4,则步长也为4。
char *b=(char*)100;//char类型每个数据字节为1,则步长也为1。
int *a=*a+1;//*a=100+1*4=104
char *b=*b+1;//*b=100+1*1=101
3.同类型指针的减法
同类型指针相减时,结果为两地的首地址相减后在除以步长(同类型指针相加乘除没有意义且是非法的)
四.指针的类型
1.基本类型:int,short,float,long,double,char。例如:
int *p//即定义了一个指向整形变量的指针
2.结构体类型
例如定义了一个结构体
struct stu{
char name[20];
int age;
}
那么该结构体指针为
struct stu*
3.数组类型——又可分为数组指针和指针数组
(1)使用指针来访问数组的首地址,例如:
int main(){
int a[5]={1,2,5,4,6};
int *p=a//或int *p=a[0],此时*p的值为a[0]即1,p为a[0]地址
*p=*(p+2);//此时p的地址变为p+2*4,恰好是a[2]的地址,所以此时*p指向的值是a[2]
}
(2)数组指针
定义为int(*p)[n]----定义了一个指向n个元素的一维数组的指针
若此时定义一个二维数组a[n][n],令p=a,那么此时*p指向a[0][0]到a[0][n-1]的n个数
此时若让p++,则*p指向了a[1][]即指向a[1][0]到a[1][n-1]的n个数
(3)指针数组
定义为int *p[3]----表示一个数组存放了p[1]p[2]p[3]三个指针变量
五.多级指针
int a;
int *pa=&a;
int **pb=&pa;
int ***pc=&pb;
a | pa | pb | |
& | &a | pb | pc |
a | &a=pa | &pa=pb | |
* | a | pa |