浅谈《C语言程序设计》中指针的应用
2012-04-29胡晓燕,庞润芳
胡晓燕,庞润芳
摘要:该文从指针的概念、运算、使用、灵活应用时应注意的事项等方面对C语言指针进行浅析和探讨。指导学生如何应用指针。
关键词:C语言;指针;指针变量;地址
中图分类号:TP311文献标识码:A文章编号:1009-3044(2012)02-0389-03
Discuss Application Of The Pointer in C Language Program
HU Xiao-yan,PANG Run-fang
(Engineering & Training Center Inner Mongolia University of Seicence and Technology, Baotou 014010, China)
Abstract: In this paper,the concept of pointer,pointer arithmetic,pointer of use, flexible application should pay attention to in terms of C language pointer analysis and discussion. Guide the students how to use the pointer.
Key words: C Langwage; Pointer; Pointer Variables; Address
《C语言程序设计》课程是我校理工科非计算机专业学生进入大学所接触的第一门计算机语言课程。实践证明,该门课程对于初学者来说难度比较大,这也是由于C语言的特点决定的。因为C语言功能强大,它既有高级语言的特点,也有低级语言的特点。而在这门课程中指针又是C语言的精华,因此灵活地应用指针,可有效地表示复杂的数据结构、动态分配内存、方便地引用字符串和数组;在进行函数调用时还可获得多个返回值,并可直接处理内存地址,实现其它高级语言难以实现的功能;运用指针编程是C语言最重要的风格之一。但指针比较难以掌握,使用时常犯一些错误,即使是熟练的程序员也很难发现和排除这些错误。为了设计出高效、简洁、紧凑的用户程序,正确理解和使用指针非常重要。因此如何引导学生学会C语言的指针在编程中应用是很重要的事情。
1指针的概念
计算机对信息的处理都由操作系统调入存储器存放并执行,存储器中有众多的存储单元,存储单元是用来存放数据的。存放在存储单元中的数据称为存储单元的内容(或值)。计算机为了对存储单元进行有效的管理,便为存储单元进行编号(以字节为单位),这个编号就是“地址”,这个“地址”又称为指针[1]。每个变量都有一个地址。不同数据类型的变量,占用的字节数不同,系统把变量占据存储单元的第一个字节的地址作为该变量的地址。有了地址我们就可以引入指针变量。指针变量是一种特殊的变量,变量中存放的不是某种数据类型的数据,而是存放另一个变量的地址。如果一个指针变量存放了另一个变量的地址,则形象地称指针变量指向那个变量。下面提供一个指针的例题,通过分析例题来理解指针的概念。
例:利用指针,求两个整数的和。main()
{ int i,j,sum;
int *p,*q;/*定义指针变量*/
p=&i;q=&j/*建立关联*/
scanf(“%d,%d”,p,q);
sum=*p+*q;/*使用指针变量*/
printf (“%d,%d ”,*p,*q);
printf(“和= %d ”,sum);
}
在程序当中,首先定义两个普通变量i,j,再定义两个指针变量p,q,为了进行区分普通变量和指针变量,所以在指针变量名前加*号。不能引用没有赋值的指针变量,否则可能会造成系统瘫痪,所以将&i赋值给p,&j赋值给q,说明指针变量指向了普通变量。如图所示:
有了指向关系,在输出语句中就可以利用指针来访问普通变量i,j。
2指针的运算
指针变量和其他变量一样,也可以进行运算,由于指针的运算实际上是地址的运算,所以和其它变量的运算又有区别[1]。
1)间接访问运算
用变量名对其所对应的存储单元的内容进行读写称为直接访问,而通过存储单元的地址对其内容进行读写的则称为间接访问。尽管指针变量中保存的是存储单元的地址,而引入指针的目的主要是为了更方便快捷地访问存储单元的内容。
间接访问是在引用的指针变量前面加一个“*”号,用来表示指针所指向的存储单元的值或内容。例如:
int a=5, *p;
p=&a
printf("%d",*p);
当指针p指向a后,若用指针p访问所指存储单元的内容时,可以写成*p,也就是说在这里*p与a是等价的。由于“&”与“*”两个运算符优先级别相同,且结合方向均为自右至左,又是一对互逆运算,所以有*&a=*p,&*p=&a。
2)指针变量加或减一个整型量,从而得到另一个地址,当然自增自减运算也是合法的。如先使p指向数组a的首地址(即p=a),则p+n表示的是下标为n的元素地址。p++表示:使p指向下一个元素a[1]。如果接着执行*p,则取出a[1]的值。*p++等价于*(p++)作用是:先得到p指向的变量的值(即*p),然后再将p+1=>p;*(p++)与*(++p)的作用不同,前者是先取*p的值,然后使p加1,而后者是先使p加1,再取*p;++ (*p)表示p所指向的元素的值加1。指针变量乘除一个整型量无意义,C语言也不允许此类语句出现。
3)由于指针变量中的地址也是一数值,所以指针变量间也可以进行关系运算。
4)两个类型相同的指针变量可以相减,例如指向同一数组的指针变量相减可以得到两个指针间元素的个数。相加或相乘则无意义[1]。
3指针的使用[3]
链表是数据结构的一种存储形式,能够实现动态分配存储空间。我们知道,用数组存放数据时,必须事先对数组定义固定的长度(即元素的个数)。例如,有的班级有100人,而有的班级有50人,如果要用同一数组先后存放不同班级的学生数据,则必须定义长度为100的数组。如果事先难以确定元素的个数,则必须把数组定义得足够大,以便够用;但实际若使用得很少,那样就造成了内存空间的浪费。定义小了又满足不了需求,为了解决这一矛盾,C语言提供了“需之则有,不需则无”的动态数据结构--链表,它根据需要开辟存储单元。
指针和结构体配合可以实现动态存储分配,用来实现对链表的建立、插入和删除等操作。
建立一个简单链表,结点类型定义的一般形式:
struct类型名
{数据域定义;
struct类型名*指针域名}
其中,数据域和指针域都可以不止一个,当指针域不止一个时,将构成比较复杂的链表。以4个结构体变量为结点建立一个简单链表并且输出。
#include
struct node
{int data;
struct node *next; };
main()
{struct node a,b,c,d,*head,*p;
head=&a/*头指针指向a结点*/
a.data=10;a.next=&b/*a结点指向b结点*/
b.data=20;b.next=&c/*b结点指向c结点*/
c.data=30;c.next=&d/*c结点指向d结点*/
d.data=40;d.next=NULL;/*d结点是尾结点*/
p=head;
while(p!=NULL)/*输出链表,p作为工作指针*/
{printf(“%d-->”,p-->data);
p=p-->next;/*工作指针后移*/}
printf(“NULL ”);}
运行结果为:
10-->20-->30-->40-->NULL
建立一个简单链表很容易,只需将引用自身的结构体变量的地址赋给前驱的next即可。在后面需增加结点(即一个此类型的结构体变量)时,只要将原链尾结构体变量中的引用自身的指针指向新增加的结点即可。
4灵活应用指针还必须注意如下问题[2]
1)要注意指针变量的当前值。我们在做指针变量指向数组的练习时,经常会有这样的情况发生:
main()
{ int a[6],i,*p;
p=a;
for(i=0;i<6;i++)
scanf(“%d”,p++);
for(i=0;i<6;i++,p++)
printf(“%d”,*p);}
当我们运行程序时,输出的6个数据和我们输入的不一致,就是由于指针变量进行了移动,已经移出了我们的数据区域,当再利用指针进行访问元素时必须把指针变量的当前值重新指向数组中的第一个元素a[0]才可以。所以上面的程序在第二个for循环的前面加一条p=a或p=&a[0];程序的结果才是正确的。
2)在一维数组a[10]中,有语句p=a,则p+i和a+i都表示地址相当于&a[i],p和a都是指针,但是它们有区别,p是变量,可以实现p++,a是常量,a的值不能改变。
3)当指针指向字符串时,字符指针变量和字符数组之间是有区别的。
A、字符数组由若干个元素组成,每个元素中存放一个字符,而字符指针变量中存放的是地址。
B、定义了字符数组之后,只能对各个数组元素赋值,不能用下面方法对字符数组赋值:char str[]; str=“I have a book!”;
而对指针变量,可以采用下面方法赋值:
char *a; a=“I have a book”;
赋给a的不是字符,是字符串的首地址。
C、对字符指针变量赋初值
char *a=“I have a book”等价于
char *a;
a=“I have a book”;
对数组初始化
char str[]=“I have a book”不等价
char str[20];
str[]=“I have a book”
5结束语
指针是C语言的难点,但也是精髓,只要我们掌握了其本质含义,也就不难了。上面所介绍的是C指针使用过程中的一些常用、重要的方法和规则。要达到熟练灵活应用,还需要在实践中不断积累、总结、提高。
参考文献:
[1]郝长胜.C语言程序设计[M].内蒙古:内蒙古大学出版社,2007.
[2]邓满英.浅析C语言指针[J].襄樊职业技术学院学报,2010(1).
[3]温娟娟.C语言中指针的探讨[J].河南职业技术师范学院学报,2003.