赵俊峰
(太原大学外语师范学院,山西 太原 030012)
指针是C语言中的一个非常重要的概念,也是C语言的精华之所在.只有掌握了指针,才能说掌握了C语言.灵活而正确地运用好指针,可以非常方便地表示复杂的数据类型,提高C语言的编程效率.指针即是地址,一个数据对象的指针即是这种数据对象的地址.要真正掌握指针,必须理解指针与变量、指针与数组、指针与字符串、指针与函数、指针与结构体之间的关系.
变量的指针即是变量的地址,若有定义:int a;则变量a的地址可以用&a获得(&为取地址运算符).
指针变量即在其中存放地址的变量.指针变量与普通变量不同,普通变量中存放的是值(可以是整数、实数或字符等),而指针变量中存放的是另一个数据对象的地址,即这个指针变量就直接指向了另一个数据对象.要使用指针变量必须经过定义、关联和引用三个阶段.
(1)定义:int a,*p;&&a为普通变量,p为指针变量.
(2)关联:p=&a;&&由于在p中存放了a的地址,指针变量p则指向a.
(3)引用:printf(“%d”,*p);&& 通过*p间接引用 p所指向的变量a.
上述的指针变量p直接指向普通变量,这种变量即为一级指针.若某个指针变量间接指向普通变量,这种指针变量则为二级指针[1].如有定义:int a,*p,**q;则 p 为一级指针,q为二级指针.若有关联:p=&a;q=&p;则q通过p间接地指向了变量a.这时,引用a的方法就有了a、*p、**q这三种形式.
一维数组的指针即是一维数组的首地址,若有定义:int a[10];则数组名a代表的即是数组的首地址.
若在一个指针变量中存放了某个一维数组的首地址,则这个指针变量就指向了这个数组中的第1个元素[2].要使用这种指针变量也必须经过定义、关联和引用三个阶段.
(1)定义:int a[10],*p;&& a为一维数组,p为指针变量.
(2)关联:p=a;或p=&a[0];&& 在p中存放了数组a的首地址,p则指向数组a的第1个元素.
(3)引用:*p、p++、*p++等等 && 通过p++可以让p指向下一个元素.
指向一维数组的指针变量不仅可以指向第一个元素,还可以在指向数组中的其他元素.如有定义:int a[10],*p=a+5;则p指针指向数组中下标为5的a[5]元素.
二维数组可以看作是特殊的一维数组.若有定义:int a[3][4];可以把第 1 行的元素 a[0][0]、a[0][1]、a[0][2]、a[0][3]看作是数组名为 a[0]的一维数组,依次类推,第2行可以看作是数组名为a[1]的一维数组,第3行可以看作是数组名为 a[2]的一维数组.而 a[0]、a[1]、a[2]又可以看作是数组名为a的一维数组,因此二维数组即是一维数组的一维数组.如下图所示,不难看出二维数组名其实是二级指针,间接地指向二维数组a的元素[3].
若在一个指针变量中存放了某个二维数组的第1个元素的地址,则这个指针变量就指向了这个数组中的第1个元素.要使用这种指针变量也必须经过定义、关联和引用三个阶段.
(1)定义:int a[3][4],*p;&& a为二维数组,p为指针变量.
(2)关联:p=&a[0][0];或 p=a[0];&& 因为 a[0]可以看作是第1行数组的数组名,因此a[0]和&a[0][0]是等价的.
(3)引用:*p、p++、*p++等等 && 通过p++可以让p指向下一个元素.
上述指针p直接指向二维数组的某一个元素,因此指针p为一级指针.p++的作用是让p指针指向下一个元素,而不是指向下一行元素.不难发现取地址运算符&和下标运算符[]是可逆的,可以相互抵消.
在上图中,我们可以发现二维数组名a指向的并不是某一个元素,它指向的是某行元素,即它指向了一行的一维数组.要使用这种指针变量也必须经过定义、关联和引用三个阶段.
(1)定义:int a[3][4],(*p)[4];&& a为二维数组,p为指向一维数组的指针变量.
(2)关联:p=&a[0];或p=a;&& 因为数组元素a[0]、a[1]、a[2]的数组名为 a,因此 a和 &a[0]是等价的.
(3)引用:p[i][j]、*(*(p+i)+j)&& 下标运算符[]和指针运算符*是等价的.
上述指针p直接指向二维数组的某一行,间接指向二维数组的某个元素,因此指针p为二级指针.p++的作用不是让p指针指向下一个元素,而是指向下一行元素[4].
数组指针即指向数组的指针,而指针数组则是元素为地址的数组.指针数组的定义如下:int*p[3];则p为长度为3的一维数组,其每个元素中都存放着地址.不难发现:无论是指向数组的指针变量,还是存放指针的数组名,都是二级指针.
字符串的指针是字符串的首地址,即字符串中第一个字符的地址.串常量代表的即是串的首地址.如串常量“abcdefg”代表的是串中第1个字符‘a’的地址.
若在一个指针变量中存放了某个字符串的首地址,则这个指针变量就指向了这个串中的第1个元素.若有定义:int*p=“abcdefg”;则指针p指向了字符a.可以通过p++或p--可以让p指向串中的下一个或上一个字符.
利用指针对字符串进行操作,要比用字符数组更简单和方便.因为数组名是地址常量,不能通过++或--指向其他字符.而指针p是地址变量,引用起来更灵活.如:语句while(*p++=*q++);的作用是将q所指字符串拷贝到p中.语句组while(*p++==*q++);return*p-*q;的作用是比较字符串是否相等.语句组while(*p)p++;while(*p++==*q++);的作用是将q所指字符串连接到p所指字符串之后.语句while(*p){if(*p>=’a’&& *p< =’z’)*p=*p-32;p++;}的作用是将p所指字符串中所有的小写字母改为大写字母.语句组n=0;while(*p)n++;的作用是求p所指字符串的长度(不包括‘ ’).
函数的指针即是函数的入口地址,函数名代表的是函数的入口地址.
若在一个指针变量中存放了某个函数的入口地址,则这个指针变量就指向了这个函数.指向函数的指针变量不能进行自加自减运算.若已定义求最大值函数max(a,b),则对指向函数max的指针变量的定义、关联和引用操作如下:
(1)定义:int(*p)();&&p为指向函数的指针变量.
(2)关联:p=max;&&在p中存放了函数max的入口地址,p则指向函数max.
(3)引用:(*p)(a,b)&& 通过p引用函数max.
返回指针的函数,即函数返回值为地址,这种函数的定义只需把函数类型和返回值都设置为指针.如下面的函数max即为返回指针的函数.
若有结构体类型定义:struct std{int age;float score;char name[10];struct std*next;};
(1)定义:struct std a,*p;&&定义p为指向结构体变量的指针变量.
(2)关联:p=&a;&&p则指向结构体变量a.
(3)引用:(*p).age=18;或p- >age=18;&& 通过p引用结构体变量a.
链表是数据存储的方式之一,它具有便于插入、删除数据等特点,在物理结构上采用非连续的存储方式,在逻辑结构上的操作是连续的.链表的创建和操作离不开指针[5].链表中的每个结点都是一个结构体变量,这些结点需要通过其指针域完成链表的连接与创建.若p指向第n结点,q指向第n+1结点,删除第n+1个结点的方法是:p->next=q->next;在p结点后插入结点r的方法是:r->next=q;p->next=r;依次输出每个结点数据域的方法是:while(p!=NULL){printf(“%d”,p- >age);p=p- >next;}.
指针是非常灵活的数据类型,指针与其他数据类型配合,可以让程序设计更加灵活和方便.掌握指针概念,首先要了解指针和其他数据类型的关系,其次还要理解&、[]、*三种运算符之间的关系:&、[]、*是可逆运算符,[]和*是等价运算符.最后还需要掌握每一种指针变量的定义、关联和引用方法.在C语言中,灵活运用指针可以达到事半功倍的程序设计效果.
[1]谭浩强.C程序设计教程[M].北京:清华大学出版社,2007.
[2]李岩.C语言程序设计基础与上机指导[M].北京:清华大学出版社,2006.
[3]马秀丽,刘志妩,李筠.C语言程序设计[M].北京:清华大学出版社,2008.
[4]祁昌平.C语言中指针使用技巧浅析[J].硅谷,2011,(8):19-20.
[5]杨立.C语言中指针的应用[J].重庆工学院学报(自然科学版),2007,(4):114 -116.