c程序设计上课课件第10讲-指针_第1页
c程序设计上课课件第10讲-指针_第2页
c程序设计上课课件第10讲-指针_第3页
c程序设计上课课件第10讲-指针_第4页
c程序设计上课课件第10讲-指针_第5页
已阅读5页,还剩140页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、廖雪峰第十讲指针C语言程序设计 The C Programming Language温州大学 瓯江学院Copyright 2012, All rights reserved. 指 针本章要求理解指针的概念;掌握指针变量的定义和使用方法;掌握指针变量作函数参数时,数据的传递方式;掌握使用指针处理一维、二维数组的方法;掌握使用指针处理字符串的方法。 本章重点指针变量的定义和使用指针变量作函数参数使用指针处理一维数组和字符串本章难点使用指针处理一维、二维数组指 针地址与指针概述变量的指针与指向变量的指针变量指针运算符与指针变量运算数组与指针字符串与指针指向函数的指针返回指针值的函数指针数组与指向指针

2、的指针本章小结参考书目及网络资源讨论时间指 针地址与指针概述变量的指针与指向变量的指针变量指针运算符与指针变量运算数组与指针字符串与指针指向函数的指针返回指针值的函数指针数组与指向指针的指针本章小结参考书目及网络资源讨论时间地址与指针概述C语言的数据是以数据类型形式出现的,C的数据类型如下:地址与指针概述指针是C语言中广泛使用的一种数据类型。运用指针编程是C语言最主要的风格之一。利用指针变量可以表示各种数据结构;能很方便地使用数组和字符串;并能象汇编语言一样处理内存地址,从而编出精练而高效的程序。地址与指针概述(contd)地址的概念 程序是由CPU控制和运行的,在执行过程中需要处理各种数据,

3、这些数据被存放在内存中。 为了便于管理,内存空间被划分成若干个大小相同(1个字节)的存储单元,里面存放着各种数据。 内存中每一个存储单元也有一个编号,这个编号被称为地址。通过地址就可以十分方便地访问指定的存储单元。如果在程序中定义了一个变量,在对程序进行编译时,系统就会给这个变量分配内存单元。变量的地址是存储它的第1个单元的编号。 地址与指针概述(contd)地 址 2001 20022003 3000 内存单元的内容00100011 000111011100110000110011 CPUBUS指针指针严格地说,一个指针是一个地址,是一个常量。而一个指针变量却可以被赋予不同的指针值,是变量。

4、但常把指针变量简称为指针。为了避免混淆,我们中约定:“指针”是指地址,是常量,“指针变量”是指取值为地址的变量。定义指针的目的是为了通过指针去访问内存单元。变量的存储与访问直接访问即系统直接根据变量的地址找到相应的存储空间。间接访问基本思想:将要访问变量a的地址存放在另一个变量p中当需要访问变量a时,先取出变量p的内容即变量a的地址再根据此地址找到变量a所对应的存储空间。能够存放其它变量地址的变量称作指针变量。 直接访问按变量地址存取变量值。假设程序已定义三个整型变量i、j、k,它们分别占用两个字节。在程序中一般是通过变量名来对内存单元进行存取操作的。事实上,编译后已经将变量名转换为变量的地址

5、,对变量的存取都是通过地址进行的。变量名与地址之间的对应关系在编译时确定的。int i, j, k;scanf(“%d”, &i);printf(“%d”, i);k=i+j间接访问假设程序已定义了一个变量i_pointer,用来存放整型变量的地址,它被分配为3010、3011两个字节。语句i_pointer=&i;将i的地址(2000)存放到i_pointer中。i_pointer的值就是2000,即变量i所占用单元的起始地址。存取变量i的值,先找到存放“i的地址”的变量i_pointer,从中取出i的地址(2000),然后到2000、2001字节取出i的值(3)。int i, *i_poi

6、nter;i_pointer=&i;地址与指针概述(contd)图(a)表示直接访问,根据变量i的地址直接对变量i的存储单元进行存取访问。图(b)则表示间接访问,先找到存放变量i地址的变量i_pointer,从其中得到变量i的地址,然后找到变量i的存储单元,对它进行存取访问。指针、指针变量 & 指针变量的值一个变量的地址称为该变量的“指针”。例如,地址2000是变量i的指针。如果有一个变量专门用来存放另一变量的地址(即指针),则它称为“指针变量”。如i_pointer就是一个指针变量。指针变量的值(即指针变量中存放的值)是地址(即指针)。为什么要为指针变量定义类型?既然指针变量的值是一个地址,

7、那么这个地址不仅可以是变量的地址,也可以是其它数据结构的地址。在一个指针变量中存放一个数组或一个函数的首地址有何意义呢? 因为数组或函数都是连续存放的。通过访问指针变量取得了数组或函数的首地址,也就找到了该数组或函数。这样一来,凡是出现数组,函数的地方都可以用一个指针变量来表示,只要该指针变量中赋予数组或函数的首地址即可。为什么要为指针变量定义类型?在C语言中,一种数据类型或数据结构往往都占有一组连续的内存单元。 用“地址”这个概念并不能很好地描述一种数据类型或数据结构,而“指针”虽然实际上也是一个地址,但它却是一个数据结构的首地址,它是“指向”一个数据结构的,因而概念更为清楚,表示更为明确。

8、 这也是引入“指针”概念的一个重要原因。指 针地址与指针概述变量的指针与指向变量的指针变量指针运算符与指针变量运算数组与指针字符串与指针指向函数的指针返回指针值的函数指针数组与指向指针的指针本章小结参考书目及网络资源讨论时间变量的指针和指向变量的指针变量变量的指针就是变量的地址。存放变量地址的变量是指针变量。即在C语言中,允许用一个变量来存放指针,这种变量称为指针变量。一个指针变量的值就是某个变量的地址或称为某变量的指针。为了表示指针变量和它所指向的变量之间的关系,在程序中用“*”符号表示“指向”。变量的指针和指向变量的指针变量为了表示指针变量和它所指向的变量之间的关系,在程序中用“*”符号表

9、示“指向”。例如,i_pointer 代表指针变量,而*i_pointer 是i_pointer 所指向的变量。因此,下面两个语句作用相同: i=3; *i_pointer=3; /*将3 赋给指针变量i_pointer所指向的变量。*/指针变量的定义格式 :基类型 *指针变量名 指针变量的命名规则与普通变量的命名规则相同。*表示所定义变量的类型为指针型。例如,int a;定义了一个整型变量a,而int *p;定义了一个指向整型变量的指针型变量p。基类型为C语言的各种类型符。如int、float、char等。其含义为该指针变量中存放的是什么类型变量的地址。指针变量的定义下面都是合法的定义:fl

10、oat *pointer_3;/ pointer_3是指向float型变量的指针变量char *pointer_4;/pointer_4是指向字符型变量的指针变量可以用赋值语句使一个指针变量得到另一个变量的地址,从而使它指向一个该变量。如:pointer_1=&i;pointer_2 =&j;指针变量的定义指针变量前面的“*”,表示该变量的类型为指针型变量。例: float *pointer_1;指针变量名是pointer_1 ,而不是*pointer_1 。 在定义指针变量时必须指定基类型。指针变量的类型必须与所指向变量的地址的变量基类型一致。下面的赋值是错误的:float a; int *

11、pointer_1; pointer_1=&a; /错误。不能将float型变量的地址放到指向整型变量的指针变量中指针变量的引用指针变量的引用指针变量同普通变量一样,使用之前不仅要定义说明,而且必须赋予具体的值。未经赋值的指针变量不能使用,否则将造成系统混乱,甚至死机。指针变量的赋值只能赋予地址, 决不能赋予任何其它数据,否则将引起错误。在C语言中,变量的地址是由编译系统分配的,对用户完全透明,用户不知道变量的具体地址。两个有关的运算符&和*&:取地址运算符。 *:指针运算符(或称“间接访问” 运算符)int a,*p1; /*定义一个整型变量a和一个指向整型变量的指针变量p1*/float

12、b,*p2; /*定义一个单精度型变量b和一个指向单精度型变量的指针变量p2*/p1=&a; /*使p1指向a,不能试图通过p1=&b;使p1指向b*/p2=&b; /*使p2指向b,不能试图通过p2=&a;使p2指向a */指针变量的访问指针变量指向另一个变量所谓将指针变量指向另一个变量,就是将另一个变量的地址赋值给指针变量。只能将数据类型与指针变量基类型相同的变量的地址赋值给指针变量。 使用地址运算符&可以获得指定变量的地址。引用指针变量 通过使用指针运算符*(或称间接访问运算符)可以间接访问指针变量所指向的变量 格式: *指针变量通过指针变量间接访问另一个变量#include main(

13、)int a=5,b=8,*p1,*p2; p1=&a;p2=&b;printf(a=%d,b=%dn,*p1,*p2);*p1=*p1+*p2; /*相当于a=a+b;*/printf(a+b=%dn,*p1); /*printf(a+b=%dn,a);*/通过指针变量访问整型变量#include main()int a, b;int *pointer_1,*pointer_2;a=100;b=10;pointer_1=&a; /*把变量a的地址赋给pointer_1 */pointer_2=&b; /*把变量b的地址赋给pointer_2 */printf( %d, %dn,a,b);pr

14、intf( %d, %dn,*pointer_1,*pointer_2);return 0;“&”和“*”运算符使用说明如果已执行了语句pointer_1=&a;&*pointer_1的含义是什么?“&”和“*”两个运算符的优先级别相同,但按自右而左方向结合,因此先进行*pointer_1的运算,它就是变量a,再执行&运算。因此,&*pointer_1与&a相同,即变量a的地址。如果已执行了语句pointer_1=&a; *&a的含义是什么?先进行&a运算,得a的地址,再进行*运算。即&a所指向的变量,即变量a。*&a和*pointer_1的作用是一样的,它们都等价于变量a。即*&a与a等价。

15、“&”和“*”运算符使用说明若有pointer_1=&a; pointer_2=&*pointer_1;它的作用是将&a (a的地址)赋给pointer_2 ; 若pointer_2原来指向b,经过重新赋值后它已不再指向b了,而指向了a。“&”和“*”运算符使用说明如果已执行了语句pointer_1=&a;(*pointer_1)+相当于a+。注意括号是必要的。由于+和*为同一优先级别,且结合方向为自右而左。#include main()int a,b,c,*pointer_1;a=5;pointer_1=&a;b=(*pointer_1)+;printf(a=%d, %dn,a,*point

16、er_1);a=5;pointer_1=&a;c=*pointer_1+;printf(a=%d, %dn,a,*pointer_1);return 0;变量的指针和指向变量的指针变量按先大后小的顺序输出两个整数a和b。#include main()int *p1,*p2,*p,a,b;scanf( %d, %d,&a,&b);p1=&a;p2=&b;if (ab) p=p1;p1=p2;p2=p;printf(a=%d,b=%dn,a,b);printf(%d,%dn,*p1,*p2);return 0;两个printf 函数作用是相同的, *p1 和*p2 就是变量a 和b。 “p1= &

17、a”和“p2=&b”不能写成“*p1=&a”和 “*p2=&b”。变量的指针和指向变量的指针变量当输入a=5,b=9时,由于ab,将p1和p2交换。交换前的情况见图(a),交换后见图(b)。变量的指针和指向变量的指针变量输入a和b两个整数,按先大后小的顺序输出a和b。#include main()void swap(int *p1,int *p2);int a,b;int*pointer_1,*pointer_2;scanf(%d,%d,&a,&b);pointer_1=&a;pointer_2=&b;if(ab) swap(pointer_1,pointer_2);printf(n%d,%d

18、n,a,b);void swap(int *p1,int *p2)int temp; temp=*p1;*p1=*p2;*p2=temp;实参pointer_1和pointer_2是指针变量,在函数调用时,将实参变量的值传递给形参变量。采取的依然是“值传递”方式。因此虚实结合后形参p1的值为&a,p2的值为&b。这时p1和pointer_1指向变量a,p2和pointer_2指向变量b。执行执行swap函数的函数体使*p1和*p2的值互换,也就是使a 和b 的值互换。函数调用结束后,p1和p2不复存在(已释放)。指针变量作为函数参数当输入a=5,b=9时,交换过程如图所示。指针变量作为函数参数

19、不能通过改变指针形参的值而使指针实参的值改变。#include main()void swap(int *p1,int *p2);int a,b;int*pointer_1,*pointer_2;scanf(%d,%d,&a,&b);pointer_1=&a;pointer_2=&b;if(ab) swap(pointer_1,pointer_2);printf(n%d,%dn,a,b);void swap(int *p1,int *p2)int *temp; *temp=*p1;*p1=*p2;*p2=*temp;*p1就是a,是整型变量。而*temp是指针变量temp所指向的变量。但tem

20、p中并无确定的值(它的值是不可预见的),因此temp所指向的单元也是不可预见的。对*temp赋值有可能给一个存储着重要数据的存储单元赋值,将会破坏系统的正常工作状况。应该将*p1的值赋给一个整型变量,如用整型变量temp作为临时辅助变量实现*p1与*p2的交换。指针变量作为函数参数#include main()void swap(int *p1,int *p2);int a,b;int *pointer_1,*pointer_2;scanf(%d,%d,&a,&b);pointer_1=&a;pointer_2=&b;printf(n%d,%dn,*pointer_1,*pointer_2);

21、if(ab) swap(pointer_1,pointer_2);printf(n%d,%dn,*pointer_1,*pointer_2);printf(n%d,%dn,a,b);void swap(int *p1,int *p2)int temp; temp=*p1;*p1=*p2;*p2=temp;指针变量作为函数参数调用函数:swap(x, y); 被调用函数:swap(int *a, int *b)实参形参 x y 5 9 a b x y 5 9 a b 5 9 x y 5 9 swap(x,y)swap(a,b)调用前 调用时 调用后 a b 小结指针变量作形参时,对应实参为数据类

22、型与该指针变量基类型相同的变量的地址。指针变量作形参时,参数传递的形式仍然为值传递。调用函数时,形参与对应实参占据着不同的存储空间,形参存储空间中存放的是对应实参的地址。在函数调用过程中,通过对实参变量的间接访问,改变了对应实参的值。当函数调用完毕后,形参的存储空间仍然被收回,但此时实参存储空间中已经保留了改变后的值,从而解决了在被调用函数中改变调用函数中变量的问题。 指 针地址与指针概述变量的指针与指向变量的指针变量指针运算符与指针变量运算数组与指针字符串与指针指向函数的指针返回指针值的函数指针数组与指向指针的指针本章小结参考书目及网络资源讨论时间指针运算符指针变量可以进行某些运算,但只能进

23、行赋值运算和部分算术运算及关系运算。取地址运算符&取地址运算符&是单目运算符,其结合性为自右至左,其功能是取变量的地址。取内容运算符*取内容运算符*是单目运算符,其结合性为自右至左,用来表示指针变量所指的变量。在*运算符之后跟的变量必须是指针变量。指针运算符指针运算符*和指针变量说明中的指针说明符*不是一回事。在指针变量说明中,“*”是类型说明符,表示其后的变量是指针类型。而表达式中出现的“*”则是一个运算符用以表示指针变量所指的变量。#include main()int a=5,*p;p=&a;/*表示指针变量p 取得了整型变量a的地址*/printf (%d,*p);/*表示输出变量a 的

24、值*/指针变量运算赋值运算:指针变量的赋值运算有以下几种形式。把一个变量的地址赋予指向相同数据类型的指针变量。例如:int a,*pa; pa=&a; /*把整型变量a 的地址赋予整型指针变量pa*/把一个指针变量的值赋予指向相同类型变量的另一个指针变量。如:int a,*pa=&a,*pb; pb=pa; /*把a 的地址赋予指针变量pb*/由于pa,pb 均为指向整型变量的指针变量,因此可以相互赋值。指针变量运算把数组的首地址赋予指向数组的指针变量。例如:int a5,*pa; pa=a;(数组名表示数组的首地址,故可赋予指向数组的指针变量pa)也可写为:pa=&a0; /*数组第一个元素

25、的地址也是整个数组的首地址, 也可赋予pa*/ 当然也可采取初始化赋值的方法:int a5,*pa=a;把字符串的首地址赋予指向字符类型的指针变量。例如:char *pc; pc=C Language;或用初始化赋值的方法写为:char *pc=C Language;这里应说明的是并不是把整个字符串装入指针变量,而是把存放该字符串的字符数组的首地址装入指针变量。指针变量运算把函数的入口地址赋予指向函数的指针变量。例如:int (*pf)(); pf=f; /*f为函数名*/加减算术运算对于指向数组的指针变量,可以加上或减去一个整数n。设pa 是指向数组a 的指针变量,则pa+n,pa-n, p

26、a+, +pa, pa-, -pa 运算都是合法的。指针变量加或减一个整数n 的意义是把指针指向的当前位置(指向某数组元素)向前或向后移动n个位置。数组指针变量向前或向后移动一个位置和地址加1 或减1 在概念上是不同的。因为数组可以有不同的类型,各种类型的数组元素所占的字节长度是不同的。加减算术运算如指针变量加1,即向后移动1 个位置表示指针变量指向下一个数据元素的首地址。而不是在原地址基础上加1。int a5,*pa;pa=a; /*pa 指向数组a,也是指向a0*/pa=pa+2; /*pa 指向a2,即pa 的值为&a2*/指针变量的加减运算只能对数组指针变量进行,对指向其它类型变量的指

27、针变量作加减运算是毫无意义的。两个指针变量之间的运算只有指向同一数组的两个指针变量之间才能进行运算,否则运算毫无意义。两指针变量相减:两指针变量相减所得之差是两个指针所指数组元素之间相差的元素个数。实际上是两个指针值(地址)相减之差再除以该数组元素的长度(字节数)。例如: pf1和pf2 是指向同一浮点数组的两个指针变量,设pf1 的值为2010H,pf2 的值为2000H,而浮点数组每个元素占4 个字节,所以pf1-pf2 的结果为(2010H-2000H)/4= 4,表示pf1 和 pf2之间相差4 个元素。两个指针变量不能进行加法运算。如: pf1+pf2 是什么意思呢?毫无实际意义。两

28、指针变量进行关系运算指向同一数组的两指针变量进行关系运算可表示它们所指数组元素之间的关系。pf1=pf2 表示pf1 和pf2 指向同一数组元素;pf1pf2 表示pf1 处于高地址位置;pf1pf2 表示pf1 处于低地址位置。指针变量还可以与0 比较。设p为指针变量,则 p=0 表明p是空指针,它不指向任何变量; p!=0 表示p 不是空指针。两指针变量进行关系运算空指针是由对指针变量赋予0 值而得到的。例如:#define NULL 0int *p=NULL;对指针变量赋0 值和不赋值是不同的。指针变量未赋值时,可以是任意值,是不能使用的。否则将造成意外错误。而指针变量赋0 值后,则可以

29、使用,只是它不指向具体的变量而已。指针运算符与指针变量运算(contd)#include main()int a=10,b=20,s,t,*pa,*pb; /*说明pa,pb 为整型指针变量*/pa=&a; /*给指针变量pa 赋值,pa 指向变量a*/pb=&b; /*给指针变量pb 赋值,pb 指向变量b*/s=*pa+*pb; /*求a+b 之和,(*pa 就是a,*pb 就是b)*/t=*pa*pb; /*本行是求a*b 之积*/printf(a=%dnb=%dna+b=%dna*b=%dn,a,b,a+b,a*b);printf(s=%dnt=%dn,s,t);指针运算符与指针变量运

30、算(contd)#include main()int a,b,c,*pmax,*pmin; /*pmax,pmin 为整型指针变量*/printf(“Input three numbers:n); /*输入提示*/scanf(%d%d%d,&a,&b,&c); /*输入三个数字*/*找出最大数和最小数*/if(ab) pmax=&a; /*指针变量赋值*/ pmin=&b; /*指针变量赋值*/ else pmax=&b; /*指针变量赋值*/ pmin=&a; /*指针变量赋值*/if(c*pmax) pmax=&c; /*判断并赋值*/if(c*pmin) pmin=&c; /*判断并赋值

31、*/printf(max=%dnmin=%dn,*pmax,*pmin); /*输出结果*/指 针地址与指针概述变量的指针与指向变量的指针变量指针运算符与指针变量运算数组与指针字符串与指针指向函数的指针返回指针值的函数指针数组与指向指针的指针本章小结参考书目及网络资源讨论时间数组与指针数组指针和指向数组的指针变量一个变量有一个地址,一个数组包含若干元素,每个数组元素都在内存中占用存储单元,它们都有相应的地址。所谓数组的指针是指数组的起始地址,数组元素的指针是数组元素的地址。指向数组元素的指针一个数组是由连续的一块内存单元组成的。数组名就是这块连续内存单元的首地址。一个数组也是由各个数组元素(下

32、标变量)组成的。每个数组元素按其类型不同占有几个连续的内存单元。一个数组元素的首地址也是指它所占有的几个内存单元的首地址。定义一个指向数组元素的指针变量int a10; /*定义a为包含10个整型数据的数组*/int *p; /*p为指向整型变量的指针*/下面是对指针变量赋值:p=&a0;把a0元素的地址赋给指针变量p。即p 指向a 数组的第0 号元素。p,a,&a0均指向同一单元,它们是数组a 的首地址,也是0 号元素a0的首地址。应该说明的是p 是变量,而a,&a0都是常量。数组与指针(contd)C语言规定,数组名代表数组的首地址,也就是第0 号元素的地址。因此,下面两个语句等价:p=&

33、a0;p=a;在定义指针变量时可以赋给初值:int *p=&a0;它等效于:int *p; p=&a0;当然定义时也可以写成: int *p=a;数组与指针(contd)数组指针变量说明的一般形式为:类型说明符 *指针变量名;其中类型说明符表示所指数组的类型。从一般形式可以看出指向数组的指针变量和指向普通变量的指针变量的说明是相同的。通过指针引用数组元素如果指针变量p已指向数组中的一个元素,则p+1指向同一数组中的下一个元素。引入指针变量后,就可以用两种方法来访问数组元素了。如果有int a5;且p的初值为&a0,则:p+i和a+i就是ai的地址,或者说它们指向a数组的第i个元素。 数组a a

34、0 a1 a2 a3 *(p+i) ai a9 p p+1, a+1 p+i, a+i p+9, a+9 通过指针引用数组元素*(p+i)或*(a+i)就是p+i 或a+i 所指向的数组元素,即ai。例如,*(p+5)或*(a+5)就是a5。指向数组的指针变量也可以带下标,如pi与*(p+i)等价。 数组a a0 a1 a2 a3 *(p+i) ai a9 p p+1, a+1 p+i, a+i p+9, a+9 数组与指针(contd)引用一个数组元素可以用:下标法:用ai形式访问数组元素。指针法:采用*(a+i)或*(p+i)形式,用间接访问的方法来访问数组元素,其中a是数组名,p是指向数

35、组的指针变量,其初值p=a。在计算数组元素ai的值时,C语言实际上先将其转换为*(a+i)的形式,然后再进行求值,因此在程序中这两种形式是等价的。如果对这两种等价的表示形式分别施加地址运算符&,便可以看出:&ai和a+i的含义也是相同的。简言之,一个通过数组下标实现的表达式可等价地通过指针和偏移量实现。数组与指针(contd)输出数组中的全部元素。(下标法)include main()int i, a10;for(i=0;i10;i+) scanf(%d,&ai);printf(n);for(i=0;i10;i+) printf(%d ,ai);return 0;数组与指针(contd)输出数

36、组中的全部元素。(通过数组名计算元素的地址,找出元素的值)#include main()int i, a10;for(i=0;i10;i+) scanf(%d,&ai);printf(n);for(i=0;i10;i+) printf(%d ,*(a+i);return 0;数组与指针(contd)输出数组中全部元素。(用指针变量指向元素)#include main()int a10;int *p,i;for(i=0;i10;i+) scanf(%d,&ai);printf(n);for(p=a;p(a+10);p+) printf(%d ,*p);return 0;数组与指针(contd)输

37、出数组中全部元素。(用指针变量指向元素)#include main()int a10=11,22,33,44,55,66,77,88,99,0, i;int *p;p=a;for(i=0;i10;) printf(a%d=%dn,i+,*p+);return 0;指针变量可以实现本身的值的改变。如p+是合法的;而a+是错误的。因为a是数组名,它是数组的首地址,是常量。数组与指针(contd)输出数组中全部元素。(用指针变量指向元素)#include main()int *p,i,a10; p=a;for(i=0;i10;i+) *p+=i;for(i=0;i10;i+) printf(a%d=

38、%dn,i,*p+);要注意指针变量的当前值。从上例可以看出,虽然定义数组时指定它包含10个元素,但指针变量可以指到数组以后的内存单元,系统并不认为非法。数组与指针(contd)输出数组中的全部元素。(用指针变量指向元素)#include main()int *p,i,a10;p=a;for(i=0;i10;i+) *p+=i;p=a;for(i=0;i10;i+) printf(a%d=%dn,i,*p+);*p+,由于+和*同优先级,结合方向自右而左,等价于*(p+)。*(p+)与*(+p)作用不同。若p 的初值为a,则*(p+)等价a0,*(+p)等价a1。(*p)+表示p所指向的元素值

39、加1。如果p当前指向a数组中的第i个元素,则: *(p-)相当于ai-;*(+p)相当于a+i;*(-p)相当于a-i。数组名作函数参数数组名可以作函数的实参和形参。如:main() int array10; f(array,10); f(int arr,int n); array为实参数组名,arr为形参数组名。数组名就是数组的首地址,实参向形参传送数组名实际上就是传送数组的地址,形参得到该地址后也指向同一数组。这就好象同一件物品有两个彼此不同的名称一样。指针变量的值也是地址,数组指针变量的值即为数组的首地址,当然也可作为函数的参数使用。在编译时是将arr按指针变量处理的,相当于将函数f的首

40、部写成:f (int *arr, int n)数组与指针(contd)将数组a中n个整数按相反顺序存放。将a0与an-1对换,再a1与an-2 对换,直到将a(n-1)/2与an-1-(int)(n-1)/2)对换。今用循环处理此问题,设两个“位置指示变量”i和j,i的初值为0,j的初值为n-1。将ai与aj交换,然后使i的值加1,j的值减1,再将ai与aj交换,直到i=(n-1)/2为止,如图所示。数组与指针(contd)将数组a中n个整数按相反顺序存放。void inv(int x,int n) /*形参x是数组名*/ int temp, i, j, m=(n-1)/2;for(i=0;i

41、=m;i+) j=n-1-i;temp=xi; xi=xj;xj=temp; main()int i,a10=3,7,9,11,0,6,7,5,4,2;printf(The original array:n);for(i=0;i10;i+) printf(%d ,ai);printf(n); inv(a,10);printf(The inverted array:n);for(i=0;i10;i+) printf(%d ,ai);数组与指针(contd)将数组a中n个整数按相反顺序存放。/*形参x 为指针变量*/void inv(int *x,int n)int temp, *p, *i, *

42、j, m=(n-1)/2;i=x; j=x+n-1; p=x+m;for(;i=p;i+,j-) temp=*i;*i=*j;*j=temp; main()int i,a10=3,7,9,11,0,6,7,5,4,2;printf(The original array:n);for(i=0;i10;i+) printf(%d ,ai);printf(n); inv(a,10);printf(The inverted array :n);for(i=0;i10;i+) printf(%d ,ai);数组与指针(contd)从10 个数中找出其中最大值和最小值。int max,min; /*全局变

43、量*/void max_min_value(int array,int n)int *p,*array_end;array_end=array+n; max=min=*array;for(p=array+1;pmax)max=*p; else if (*pmin)min=*p;main()int i,number10;printf(“Enter 10 integer umbers:n);for(i=0;i10;i+) scanf(%d,&numberi);max_min_value(number,10);printf(max=%d,min=%d,max,min);函数max_min_value

44、中的语句:max=min=*array; array是数组名,它接收从实参传来的数组number 的首地址。*array相当于*(&array0)。上述语句与max=min=array0;等价。执行for循环时,p的初值为array+1,即p指向array1。以后每次执行p+,使p指向下一个元素。每次将*p和max与min比较。将大者放入max,小者放min。函数max_min_value 的形参array 可以改为指针变量类型。实参也可以不用数组名,而用指针变量传递地址。数组与指针(contd)实参也可以不用数组名,而用指针变量传递地址。int max,min; /*全局变量*/void m

45、ax_min_value(int *array, int n)int *p,*array_end;array_end=array+n;max=min=*array;for(p=array+1;pmax) max=*p; else if (*pmin) min=*p;main()int i,number10,*p;p=number; /*使p 指向number 数组*/printf(“Enter 10 integer umbers:n);for(i=0;i10;i+,p+) scanf(%d,p);p=number;max_min_value(p,10);printf(max=%d,min=%d

46、,max,min);int max,min; /*全局变量*/void max_min_value(int array, int n)int *p,*array_end;array_end=array+n; max=min=*array;for(p=array+1;pmax) max=*p; else if (*pmin)min=*p;main()int i,number10;printf(“Enter 10 integer umbers:n);for(i=0;i10;i+) scanf(%d, &numberi );max_min_value(number,10);printf(max=%d

47、,min=%d,max,min);数组与指针(contd)归纳起来,如果有一个实参数组,想在函数中改变此数组中的元素的值,实参与形参的对应关系有:形参和实参都用数组名,如:main()int a10; f(a,10) f(int x,int n) 数组与指针(contd)实参用数组,形参用指针变量。实参a为数组名,形参x为指向整型变量的指针变量,函数执行时,x指向a0,即x=&a0,如下图。通过改变x的值,从而可以指向a数组的任一元素。main()int a10;f(a,10) f(int *x, int n)数组与指针(contd)实参、形参都用指针变量。实参p和形参x都为指针变量。先使实参

48、指针变量p指向数组a,p的初值为&a0。然后,将p的值传给形参指针变量x,x的初值也为&a0,如下图。通过x值的改变可以使x指向数组a的任一元素。void main()int a10, *p=a; f(p, 10); void f(int *x, int n)数组与指针(contd)实参为指针变量,形参为数组名。实参p为指针变量,它指向a0。形参为数组名x,编译系统把x作为指针变量处理,将a0的地址传给形参x,使指针变量x指向a0。也可以理解为形参数组x和a数组共用同一段内存单元,如下图。在函数执行过程中,使xi的值发生变化,而xi就是ai。这样主函数就可以使用变化了的数组元素值。 void

49、main()int a10, *p=a; f(p,10); void f(int x, int n) 数组与指针(contd)将数组a中n个整数按相反顺序存放(实参形参均用指针变量) 。#include void inv(int *x, int n)int temp, *p, *i, *j, m=(n-1)/2;i=x; j=x+n-1; p=x+m;for(;i=p;i+,j-) temp=*i;*i=*j;*j=temp; main()int i,a10=3,7,9,11,0,6,7,5,4,2, *p;printf(The original array:n);for(i=0;i10;i+

50、) printf(%d ,ai);printf(n); p=a; inv(a,10);printf(The inverted array :n);for(p=a;pa+10;p+) printf(%d ,*p);main函数中不能省去第一个“p=a”。因为,如果用指针变量作实参,必须先使指针变量有确定值,指向一个已定义的单元。能不能省去第二个“p=a”?为什么?指向多维数组的指针和指针变量二维数组指针变量说明的一般形式为:类型说明符 (*指针变量名)长度其中“类型说明符”为所指数组的数据类型。“*”表示其后的变量是指针类型。“长度”表示二维数组分解为多个一维数组时,一维数组的长度,也就是二维数

51、组的列数。应注意:“(*指针变量名)”两边的括号不可少,如缺少括号则表示是指针数组,意义就完全不同了。指向多维数组的指针和指针变量把二维数组a 分解为一维数组a0,a1,a2之后,设p为指向二维数组的指针变量。可定义为:int (*p)4它表示p是一个指针变量,它指向包含4个元素的一维数组。若指向第一个一维数组a0,其值等于a,a0,或&a00等。而p+i则指向一维数组ai。*(p+i)+j是二维数组i行j列的元素的地址,而*(*(p+i)+j)则是i 行j 列元素的值。多维数组的地址设有整型二维数组a23,设数组a的首地址为2000,各下标变量的首地址及其值如下图。数组与指针(contd)用

52、指针变量输出多维数组元素的值。#include main()int a34=0,1,2,3, 4,5,6,7, 8,9,10,11;int i, j, (*p)4;p=a;printf(%o,%o,%o,%on,p,a,a0,&a00);for(i=0;i3;i+) for(j=0;j4;j+) printf(%2d ,*(*(p+i)+j); printf(n);int (*p)4表示p是一个指针变量,它指向包含4个元素的一维数组。若指向第一个一维数组a0,其值等于a、a0 或&a00等。而p+i则指向一维数组ai。*(p+i)+j是二维数组i行j列的元素的地址,而*(*(p+i)+j)则是

53、i行j列元素的值。数组与指针(contd)用指针变量输出二维数组元素的地址和值。#include void main()int a34=1,3,5,7, 9,11,13,15, 17,19,21,23;int *p;for(p=a0;pa0+12;p+) printf(addr=%o,p); printf(value=%2dn,*p); return 0; p是一个指向整型变量的指针变量,它可以指向一般的整型变量,也可以指向整型的数组元素。p的值是数组元素的地址,而*p是数组元素的值。数组与指针(contd)#include #define FMT %d,%dnvoid main()int a

54、34=1,2,3,4,5,6,7,8, 9,10,11,12;printf(FMT,a,*a);printf(FMT,a0,*(a+0);printf(FMT,&a0,&a00);printf(FMT,a1,(a+1);printf(FMT,&a10,*(a+1)+0);printf(FMT,a2,*(a+2);printf(FMT,&a2,a+2);printf(FMT,a10,*(*(a+1)+0);printf(FMT,*a2,*(*(a+2)+0);0行首地址和0行0列元素地址0行0列元素地址0行0首地址和0行0列元素地址1行0列元素地址和1行首地址1行0列元素地址2行0列元素地址2行

55、首地址1行0列元素的值2行0列元素的值数组与指针(contd)用指向数组的指针作函数参数一维数组名可以作为函数参数传递,多维数组也可以作函数参数传递。在用指针变量作形参以接受实参数组名传递来的地址时,有两种方法:用指向变量的指针变量用指向一维数组的指针变量例:有一个班,3个学生,各学4门课,计算总平均分数以及第n个学生的成绩。分析:可以使用指向数组的指针作函数参数而举的例子。用函数average求总平均成绩,用函数search找出并输出第i个学生的成绩。数组与指针(contd)#include void average(float *p,int n)float *p_end, sum=0;p_

56、end=p+n-1;for(;p=p_end;p+) sum=sum+(*p);printf(“Average=%5.2fn, sum/n);void search(float (*p)4,int i)int j; printf(“Scores of No.%d:n,i+1); for(j=0;j4;j+) printf(%5.2f ,*(*(p+i)+j);main()float score34=65,67,70,60, 80,87,90,81,90,99,100,98; average(*score,12); search(score,2);在函数average中形参p被声明为指向浮点型变

57、量的指针变量,实参用*score,即score0,也就是&score00。将&score00的地址传给p,使p指向score00。然后使p先后指二维数组的各个元素。函数search的形参则是指向包含4个元素的一维数组的指针变量。i为学生序号(0,1,2)。将实参score的值(代表该数组0行起始地址)传给p,使p也指向score0。p+i是scorei的起始地址,*(p+i)+j是scoreij的地址,*(*(p+i)+j)是scoreij的值。数组与指针(contd)#include void search(float (*p)4,int n)int i,j,flag;for(j=0;jn;

58、j+) flag=0; for(i=0;i4;i+) if(*(*(p+j)+i)60) flag=1; if(flag=1) printf(No.%d fails:n,j+1); for(i=0;i4;i+) printf(%5.1f ,*(*(p+j)+i); printf(n);main()float score34=65,67,70,60, 80,87,90,81,90,99,100,98; search(score,3);实例是“查找有一门以上课程不及格的学生,并输出他们全部的课程成绩”。函数search的形参则是指向包含4个元素的一维数组的指针变量。将实参score的值(代表该数组

59、0行起始地址)传给p,使p也指向score0。变量j代表学生的序号(0,1,2),i代表学生课程号。p+j是scorej的起始地址,*(p+j)+i是scoreji的地址,*(*(p+j)+i)是scoreji的值。数组与指针在C语言中,指针和数组之间的关系十分密切,通过数组下标所能完成的任何操作都可以通过指针来实现。虽然用指针实现的程序理解起来稍微困难一些,但一般来说,用指针编写的程序比数组下标编写的程序执行速度快。“In C, there is a strong relationship between pointers and arrays, Any operation that can

60、 be achieved by array subscripting can also be done with pointers. The pointer version will in general be faster but, at least to the uninitiated, somewhat harder to understand.” - Brian W. Kernighan and Dennis M. Ritchie. The C programming Language. 5.3 Pointers and Arrays.指 针地址与指针概述变量的指针与指向变量的指针变量

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论