指针是C语言的难点,本篇文章总结一下各类指针的用法。
指针是个变量,它存储的是变量的地址,这个地址指向哪里,取决于指针的类型,指针类型包括以下几种:
基本类型指针
数组类型指针
函数类型指针
结构体类型指针
联合体类型指针
指针类型指针
无具体类型指针
下面阐述各个类型指针的使用方法。
一.基本类型指针声明方式:
基本类型*p;
变量p是一个基本类型指针,p存储的是基本类型变量的地址,表示p指向了基本类型,基本类型包括char,short,int,float,long,double。
例如int*p,p就变成了一个整型指针,如下图
使用例子:
#include <stdio.h>
void swap(int* a, int* b);
int main(int args, char *argv[]) {
int a = 10;
int b = 20;
int*pa = &a;//获取变量a的地址赋值给指针pa
int* pb = &b;
printf("%i\n", *pa);//输出10
*pa = *pa 1;
printf("%i\n", *pa);//输出11
int* clonep = pa;
printf("%i\n", *clonep);//输出11
clonep = pb;
printf("%i\n", *clonep);//输出20
int c = *pa;
printf("%i\n", c);//输出11
c = c 1;
printf("%i\n", c);//输出12
printf("%i\n", *pa);//输出11
// 互换pa和pa指向的变量的值
swap(pa, pb);
printf("%i\n", a);//输出20
printf("%i\n", b);//输出11
}
// 互换a和b两个变量的值
void swap(int* a, int* b) {
int temp = *a;
*a = *b;
*b = temp;
}
从上面代码的例子,可以看出以下几点:
a.通过&运算符可以获取一个变量的地址,&运算符只能获取内存变量的地址,不能对常量或者寄存器变量进行&操作。
b.可以通过*p,获取指针p指向的变量的值。
c.函数调用时,会把传入的变量拷贝一份作为参数,这里的拷贝就是把变量的值拷贝了一份,自此后,参数就是一个新的变量,它与传入的变量的值相同,任何对参数值的修改,都不会影响到传入的变量。
指针也是变量,只不过指针的值是地址罢了,所以也可以把指针变量传入给函数作为参数(代码21行),函数调用时,会把传入的指标变量拷贝一份作为参数,这个参数就是一个新的指针变量,它与传入的指针变量指向了同一个地址,所以在函数内部可以对这个参数指针指向的变量进行操作,效果与传入的指针变量一样。
二.数组类型指针一维数组类型指针的声明方式:
T (*p)[N];
变量p是一个数组指针,p存储的是一维数组T[N]的地址,表示p指向了一维数组,一维数组的长度为N,一维数组每一项的数据类型为T,T可以是基本类型,指针,结构体,联合体。
例如int (*p)[2] 表示p指向了一维整型数组,这个整型数组长度为2,如下图是一个二维数组a[3][2],这个二维数组由3个一维数组(每个一维数组有2个整型元素)组成。
一维数组指针
使用例子
#include <stdio.h>
int main(int args, char *argv[]) {
int a[3][2] = { {1,2},{3,4},{5,6} };
int(*p)[2] = a;
printf("%i\n", **p );//输出1
printf("%i\n", **p );//输出3
printf("%i\n", **p);////输出5
p = &a[0];
printf("%i\n", ** p);//输出3
printf("%i\n", ** p);//输出5
printf("%i\n", **p);////输出5
}
上面代码例子定义了一个二维数组a[3][2]
第4行代码:int(*p)[2] = a;a是二维数组的首地址,它是一个常量,所以可以直接赋值给p,a与一维数组a[0]的地址相同即a=&a[0],此时p存储的就是一维数组a[0]的地址,指向了一维数组a[0]。
第5行代码:**和 运算都属于一元运算符,它们的优先级相同,但运算方向是从右向左的,因此先执行p ,而p 的意思是先操作p变量,然后再将p变量 1,这里操作p变量的意思是先执行**p,为什么需要两个*才能获取到二维数组的元素值呢,原因如下:
**p是从右向左执行的,先执行右边的*,因此先执行*p,*p的意思获取p指向的变量,而p指向的是一维数组,所以*p的结果就是a[0],a[0]是个一维数组,所以**p=*(a[0]),C语言规定,对数组可以执行*操作时,会临时转化为一个指针,因此可以a[0]就临时变成了一个指针,再次对a[0]进行*操作后,就获取到了a[0]这个一维数组第一个元素的值即1。
第6行代码:第5行代码p 后,p指向了a[1]的地址,如下图
类似于第5行代码的执行方式,此时**p 后,获取的变量值为a[1]的第一个元素即3
第7行代码:第6行代码p 后,p指向了a[2]的地址,如下图