清华谭浩强C语言教学-第10章 指针ppt课件_第1页
清华谭浩强C语言教学-第10章 指针ppt课件_第2页
清华谭浩强C语言教学-第10章 指针ppt课件_第3页
清华谭浩强C语言教学-第10章 指针ppt课件_第4页
清华谭浩强C语言教学-第10章 指针ppt课件_第5页
已阅读5页,还剩139页未读 继续免费阅读

下载本文档

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

文档简介

1、第十章 主要内容 10.1地址和指针的概念 10.变量的指针和指向变量的 指针变量 10.数组与指针 10.字符串与指针 10.指向函数的指针 10.返回指针值的函数 10.指针数组和指向指针的指针 10.8有关指针的数据类型和指针运算的小结 10.1地址和指针的概念(1计算机硬件系统的内存储器中,拥有大计算机硬件系统的内存储器中,拥有大量的存储单元容量为字节)。量的存储单元容量为字节)。为了方便管理,必须为每一个存储单元编号,为了方便管理,必须为每一个存储单元编号,这个编号就是存储单元的这个编号就是存储单元的“地址地址”。每个存储单。每个存储单元都有一个惟一的地址。元都有一个惟一的地址。 1

2、.内存地址内存地址内存中存储单元的编号内存中存储单元的编号(2在地址所标识的存储单元中存放数据。在地址所标识的存储单元中存放数据。注意:内存单元的地址与内存单元中的数据注意:内存单元的地址与内存单元中的数据是两个完全不同的概念。是两个完全不同的概念。2.变量地址变量地址系统分配给变量的内存单元的系统分配给变量的内存单元的起始地址起始地址假设有这样一个程序:假设有这样一个程序: main() int num; scanf(%d,&num); printf(num=%dn, num); C编译程序编译到该变量定义语句时,将变量num 登录到“符号表中。符号表的关键属性有两个:一是“标识符名

3、id)” ,二是该标识符在内存空间中的“地址addr)” 。为描述方便,假设系统分配给变量num的2字节存储单元为 2000 和2019,则起始地址2000就是变量num在内存中的地址。 3.变量值的存取通过变量在内存中的地址进行系统执行“scanf(”%d“,&num);”和“printf(”num=%dn“, num);”时,存取变量num值的方式可以有两种: (1)直接访问直接利用变量的地址进行存取 1)上例中scanf(“%d”,&num)的执行过程是这样的: 用变量名num作为索引值,检索符号表,找到变量num的起始地址2000;然后将键盘输入的值假设为送到内存单元2

4、000和2019中。此时,变量num在内存中的地址和值 2printf(num=%dn,num)的执行过程,与scanf()很相似: 首先找到变量num的起始地址2000,然后从2000和2019中取出其值,最后将它输出。 (2间接访问通过另一变量访问该变量的值 语言规定:在程序中可以定义一种特殊的变量称为指针变量),用来存放其它变量的地址。例 如 , 假 设 定 义 了 这 样 一 个 指 针 变 量num_pointer,它被分配到4000、4001单元,其值可通过赋值语句“num_pointer=num;”得到。此时,指针变量num_pointer的值就是变量num在内存中的起始地址20

5、00.通过指针变量num_pointer存取变量num值的过程如下:首先找到指针变量num_pointer的地址4000),取出其值2000正好是变量num 的起始地址); 然后从2000、2019中取出变量num的值3)。 在语言中,指针是一种特殊的变量,它是在语言中,指针是一种特殊的变量,它是存放地址的。存放地址的。(3两种访问方式的比较两种访问方式的比较 两种访问方式之间的关系,可以用某人甲系两种访问方式之间的关系,可以用某人甲系统要找某人乙变量来类比。统要找某人乙变量来类比。一种情况是,甲知道乙在何处,直接去找就是一种情况是,甲知道乙在何处,直接去找就是即直接访问)。即直接访问)。另一

6、种情况是,甲不知道乙在哪,但丙指针另一种情况是,甲不知道乙在哪,但丙指针变量晓得,此时甲可以这么做:先找丙,变量晓得,此时甲可以这么做:先找丙,从丙处获得乙的去向,然后再找乙即间接从丙处获得乙的去向,然后再找乙即间接访问)。访问)。指针和指针变量的定义:指针和指针变量的定义: 一个变量的地址称为该变量的“指针”。 例如,地址2000是变量的指针。如果有一个变量专门用来存放另一变量的地址即指针),则它称为“指针变量”。上述的i_pointer就是一个指针变量。为表示指针变量和它指向的变量之间的关系,用指针运算符为表示指针变量和它指向的变量之间的关系,用指针运算符“*”表示。表示。 例如,指针变量

7、例如,指针变量num_pointer与它所指向的变量与它所指向的变量num的关系,的关系,表示为:表示为:*num_pointer,即,即*num_pointer等价于变量等价于变量num。因而,下面两个语句的作用相同:因而,下面两个语句的作用相同:num=3; /*将将3直接赋给变量直接赋给变量num*/num_pointer=# /*使使num_pointer指向指向num */*num_pointer=3; /*将将3赋给指针变量赋给指针变量num_pointer所所指向的变量指向的变量*/ 10.2 变量的指针和指向变量的指 针变量10.10.1 .1 定义一个指针变量

8、定义一个指针变量定义指针变量的一般形式为基类型 *指针变量名;下面都是合法的定义:float *pointer_; char *pointer_; 可以用赋值语句使一个指针变量得到另一个变量的地址,从而使它指向一个该变量。例如:pointer_;pointer_;在定义指针变量时要注意两点:在定义指针变量时要注意两点:指针变量前面的指针变量前面的“*”,表示该变量的类型为指针型,表示该变量的类型为指针型变量。变量。例例: float *pointer_1;指针变量名是指针变量名是pointer_1 ,而不是,而不是* pointer_1 。 (2) 在定义指针变量时必须指定基类型。在定义指针变

9、量时必须指定基类型。需要特别注意的是,只有整型变量的地址才能放到需要特别注意的是,只有整型变量的地址才能放到指向整型变量的指针变量中。下面的赋值是错误指向整型变量的指针变量中。下面的赋值是错误的的 float a; int * pointer_1; pointer_1=&a; 10.2.2 10.2.2 指针变量的引用指针变量的引用 注意注意:指针变量中只能存放地址指针),指针变量中只能存放地址指针),不要将一个整数或任何其他非地址类型的数据)不要将一个整数或任何其他非地址类型的数据)赋给一个指针变量。赋给一个指针变量。 例例10. 通过指针变量访问整型变量通过指针变量访问整型变量#i

10、nclude voidmain ( ) int ,; int*pointer_, *pointer_; ; pointer_; /*把变量的地址赋给 pointer_1 */ pointer_; /*把变量的地址赋给 pointer_ */printf(%,%,);printf(%,%,*pointer_, *pointer_); 对对“”和和“* *”运算符说明:运算符说明:如果已执行了语句如果已执行了语句 pointer_pointer_;(1)(1)* * pointer_ pointer_的含义是什么?的含义是什么? “ “”和和“* *”两个运算符的优先级别两个运算符的优先级别相同,

11、但按自右而左方向结合。因而,相同,但按自右而左方向结合。因而,* * pointer_pointer_与相同,即变量与相同,即变量a a的地址。的地址。 如果有如果有pointer_2 pointer_2 * * pointer_ pointer_ ;它的作用是将的地址赋给它的作用是将的地址赋给pointer_2 pointer_2 ,如果,如果pointer_2pointer_2原来指向,经原来指向,经过重新赋值后它已不再指向了,而指向了。过重新赋值后它已不再指向了,而指向了。(2) *的含义是什么?的含义是什么? 先进行运算,得的地址,再进行先进行运算,得的地址,再进行*运算。运算。*和和

12、*pointer_的作用是一样的,它们都等价于变的作用是一样的,它们都等价于变量。即量。即*与等价。与等价。(3) (*pointer_)相当于。)相当于。例例10 . 2 输入和两个整数,按先大后小的顺序输出输入和两个整数,按先大后小的顺序输出 和。和。#include void main() int *1,*2,*,; scanf(,);1; if);printf(=,=,); printf(max=,min=,*1,*2); 运行情况如下:运行情况如下:, ,当输入,时,由于,当输入,时,由于,将和交换。交换前的情况见图将和交换。交换前的情况见图),交换后见图)。),交换后见图)。注意:

13、此例中注意:此例中a和和b并未交并未交换,而换,而p1和和p2的值改变。的值改变。10.10.3 .3 指针变量作为函数参数指针变量作为函数参数例例10 . 3 对输入的两个整数按大小顺序输出对输入的两个整数按大小顺序输出 #include void main()void swapint *,int *);int ,;int *pointer_,*pointer_; scanf(,);pointer_ ; pointer_2 ; if)swap( pointer_ , pointer_2 );printf(,); void swapint *,int *) int temp; temp*1;

14、*; *temp; 注意:此例中注意:此例中a和和b已经交换,而已经交换,而pointer_ , pointer_2的值未改变。被调用函数不的值未改变。被调用函数不能改变实参指针变量的值,但可以改变它能改变实参指针变量的值,但可以改变它们所指向的变量的值。们所指向的变量的值。为了利用被调用函数改变的变量值,应该使为了利用被调用函数改变的变量值,应该使用指针或指针变量作函数实参。其机用指针或指针变量作函数实参。其机制为:在执行被调用函数时,使形参指针制为:在执行被调用函数时,使形参指针变量所指向的变量的值发生变化;函数调变量所指向的变量的值发生变化;函数调用结束后,通过不变的实参指针或实参用结束

15、后,通过不变的实参指针或实参指针变量将变化的值保留下来。指针变量将变化的值保留下来。例例10. 输入、输入、 3个整数,按大小顺序输出。个整数,按大小顺序输出。#include void main() void exchangeint *1, int *2, int *3); int ,*,*,*; scanf(%,%,%,&, &, &); exchange (,); printf(,); void exchangeint *, int *, int *) void swapint *, int *); if(*) swap,); if(*) swap,); if(*

16、 swap,); void swapint *, int *) int temp; temp*; *; *temp; 10.3 数组与指针 一个变量有地址,一个数组包含若干元素,每个数组元素都在内存中占用存储单元,它们都有相应的地址。指针变量既然可以指向变量,当然也可以指向数组元素把某一元素的地址放到一个指针变量中)。所谓数组元素的指针就是数组元素的地址。 10.3.1 10.3.1 指向数组元素的指针指向数组元素的指针数组的指针数组的指针数组在内存中的起始地址,数组元数组在内存中的起始地址,数组元素的指针素的指针数组元素在内存中的起始地址。数组元素在内存中的起始地址。2.指向数组的指针变量的

17、定义指向数组的指针变量的定义指向数组的指针变量的定义,与指向普通变量的指向数组的指针变量的定义,与指向普通变量的指针变量的定义方法一样。指针变量的定义方法一样。例如:例如: ; (定义为包含个整型数据的数组定义为包含个整型数据的数组)*; (定义为指向整型变量的指针变量定义为指向整型变量的指针变量)应当注意,如果数组为型,则指针变量的应当注意,如果数组为型,则指针变量的基类型亦应为型。基类型亦应为型。 对该指针变量赋值:对该指针变量赋值:;把元素的地址赋给指针变量。也就是使把元素的地址赋给指针变量。也就是使指向数组的第号元素,如图:指向数组的第号元素,如图:在在C中中,数组名代表数组的首地址。

18、因此数组名代表数组的首地址。因此p=a ; 与与p=&a0;是等价的。是等价的。p = a ; 是将是将a 数组的首地址赋给指针变量数组的首地址赋给指针变量p。但这里的。但这里的a 并不代表整个数组。并不代表整个数组。上面定义可写成上面定义可写成: int*p=a;作用是把作用是把a数组首元素地址赋给指针变量数组首元素地址赋给指针变量p不是不是*p)10.10. .通过指针引用数组元素通过指针引用数组元素 若若p = a ; 是将整型数组是将整型数组a的首地址赋给整型指针变量的首地址赋给整型指针变量 p,那么,那么 *p=5; 是将整数是将整数5赋给赋给a数组的第一个元素数组的第一个元

19、素a0,等价于,等价于a0=5 。 p+1表示指针变量表示指针变量p当前所指的数组元素的下一个元素。但当前所指的数组元素的下一个元素。但p+1 不是不是p的值加的值加 1 。若有。若有 p=&a0; 那么那么 p+i (或或a+i) 就是就是 a i 的地址的地址 (因为因为a代表数组代表数组a的首地址的首地址)。 若有若有p=&a0; 那么那么*(p+i)或或*(a+i)就是就是p+i或或a+i所指向的数组元素,所指向的数组元素, 即即ai。也就是说。也就是说 *(p+i) = *(a+i) = ai。 指向数组的指针变量可以带下标,如:指向数组的指针变量可以带下标,如:pi

20、 与与 *( p+i)是等价的。是等价的。引用一个数组元素,可以用:() 下标法,如形式;() 指针法,如*(或*()。其中是数组名,是指向数组元素的指针变量,其初值。例例10.5 输出数组中的全部元素。输出数组中的全部元素。 假设有一个数组,整型,有个元素。要输出各元素的值有三种方法: (1)下标法。#include void main() int ; int;for;)scanf(,); printf();for;)printf(,); (2) 通过数组名计算数组元素地址,找出元素的值。#include voidmain() int ; int ;for; )scanf(,);printf

21、(); for;) printf(,*(); (3) 用指针变量指向数组元素。#include void main() int ; int *,; for;) scanf(,); printf(); for;();) printf( ,*); 这三种方法比较这三种方法比较: 1.前两种效率相同,每次都要计算元素地址,前两种效率相同,每次都要计算元素地址,费时较多。费时较多。 2.第三种方法用指针变量直指元素,不必每第三种方法用指针变量直指元素,不必每次从新计算地址,像次从新计算地址,像P+这样的运算速度很这样的运算速度很快,所以能大量提高执行效率。快,所以能大量提高执行效率。 3.下标法比较直

22、观,能直接知道是第几个元下标法比较直观,能直接知道是第几个元素,地址法或指针法不直观,需要仔细分析素,地址法或指针法不直观,需要仔细分析地址和指针的指向。地址和指针的指向。 几个注意的问题: 指针变量可以实现本身的值的改变。如p+是合法的;而a+是错误的。因为a是数组名,它是数组的首地址,是常量。 要注意指针变量的当前值。请看下面的程序:例例10. 通过指针变量输出数组的个元素。通过指针变量输出数组的个元素。 #include void main() int*,;for; )scanf(,); printf(); for;, ) printf(,*);程序运行情况:程序运行情况:1 2 3 4

23、 5 6 7 8 9 0 22153 234 0 0 30036 25202 11631 8259 8237 28483显然输出的数值并不是数组中各元素的值显然输出的数值并不是数组中各元素的值 #include void main() int*,;for;)scanf(,); printg(); p=a; for;, ) printf(,*);从上例可以看出,虽然定义数组时指定它包含从上例可以看出,虽然定义数组时指定它包含10个元素,但指针变量可以指到数组以后的内存单个元素,但指针变量可以指到数组以后的内存单元,系统并不认为非法。元,系统并不认为非法。*p+,由于,由于+和和*同优先级,结合方

24、向自右而左,同优先级,结合方向自右而左,等价于等价于*(p+)。*(p+)与与*(+p)作用不同。若作用不同。若p的初值为的初值为a,那么,那么*(p+)等价等价a0,*(+p)等价等价a1。(*p)+表示表示p所指向的元素值加所指向的元素值加1。如果如果p当前指向当前指向a数组中的第数组中的第i个元素,那么个元素,那么*(p-)相当于相当于ai-;*(+p)相当于相当于a+i;*(-p)相当于相当于a-i。10.10.3 .3 用数组名作函数参数用数组名作函数参数在第在第8章章8.7节中介绍过可以用数组名作函数的参数节中介绍过可以用数组名作函数的参数如:如: void main()() ii

25、nt arr,int ); int array; array,);,); void (int arr,int ) array为实参数组名,arr为形参数组名。在学习指针变量之后就更容易理解这个问题了。数组名就是数组的首地址,实参向形参传送数组名实际上就是传送数组的地址,形参得到该地址后也指向同一数组。这就好象同一件物品有两个彼此不同的名称一样。 同样,指针变量的值也 是地址,数组指针变量 的值即为数组的首地址 ,当然也可作为函数的 参数使用。例例10 将数组中个整数按相反顺序存放。将数组中个整数按相反顺序存放。#include void main()() void invint ,int );

26、 int , ,;,;printf(The original array:););for;);)printf (,);,);printf();); inv (,);(,); printf(The array has been in verted:);); for;);) printf (,);,); printf (););void invint ,int ) /*形参x是数组名*/ int temp,();for;) ;temp; ; temp; return; 运行情况如下:运行情况如下:The original array:,The array has been inverted:,如果

27、有一个实参数组,想在函数中改变此数如果有一个实参数组,想在函数中改变此数组中的元素的值,实参与形参的对应关系有组中的元素的值,实参与形参的对应关系有以下种情况:以下种情况: (1) 形参和实参都用数组名,如:形参和实参都用数组名,如:void main()() void int ,int ) int ; ,);,); (2) 实参用数组名,形参用指针变量。如:实参用数组名,形参用指针变量。如:void ()() void int *,int )int ; ,);,); (3)实参形参都用指针变量。例如:实参形参都用指针变量。例如:void main()() void int *,int )in

28、t , *p=a; p,);,); (4) 实参为指针变量,形参为数组名。如:实参为指针变量,形参为数组名。如: void main()() void int x ,int ) ,*p=a; p,);,); #include void main()() void invint *,int ); int ,*; printf(The original array:n );); for;,);,)scanf(,);,);printf();); ; inv,);,); /* 实参为指针变量实参为指针变量 ,一定一定 要有确定值要有确定值*/ printf(The array has been inv

29、erted :);); for; ) printf(,*);); printf();); void invint *,int )int,temp,*,*;(); ;for(;,)emp*;*;*temp;return; 例例109 用选择法对个整数按由大到小顺序排序。用选择法对个整数按由大到小顺序排序。 #include void main() void sortint ,int ); int*,10; ; for;) scanf(,); ; sort,); for,;)(,*);void sortint ,int )/*把x改为*x,下面不 int ,; 变,程序依然合法*/ for;);f

30、or;) ; !); ; ; 10.3.4 10.3.4 多维数组与指针多维数组与指针 用指针变量可以指向一维数组中的元素,也可以指向多维数组中的元素。但在概念上和使用上,多维数组的指针比一维数组的指针要复杂一些。 1. 1. 多维数组元素的地址多维数组元素的地址先回顾一下多维数组的性质,可以认为二维数组是“数组的数组”,例 :定义int a34=0,1,2,3,4,5,6,7,8,9,10,11则二维数组a是由3个一维数组所组成的。设二维数组的首行的首地址为1 ,那么各下标变量的首地址及其值如图所示。各下标变量的首地址及其值如图所示。语言允许把一个二维数组分解为多个一维数组来语言允许把一个二

31、维数组分解为多个一维数组来处置。因此数组处置。因此数组a可分解为三个一维数组,即可分解为三个一维数组,即a0,a1,a2。每一个一维数组又含有四个元素。每一个一维数组又含有四个元素。 数组及数组元素的地址表示如下:数组及数组元素的地址表示如下: 从二维数组的角度来看,从二维数组的角度来看,a是二维数组名,是二维数组名,a代表整代表整个二维数组的首地址,也是二维数组个二维数组的首地址,也是二维数组0行的首地址,行的首地址,等于等于1000。a+1代表第一行的首地址,等于代表第一行的首地址,等于1008。如图:如图: a0是第一个一维数组的数组名和首地址,因此也是第一个一维数组的数组名和首地址,因

32、此也为为1000。*(a+0)或或*a是与是与a0等效的,等效的, 它表示一维它表示一维数组数组a00 号元素的首地址,也为号元素的首地址,也为1000。&a00是二维数组是二维数组a的的0行行0列元素首地址,同样是列元素首地址,同样是1000。因而,因而,a,a0,*(a+0),*a,&a00是相等的。是相等的。 同理,同理,a+1是二维数组是二维数组1行的首地址,等于行的首地址,等于1008。a1是第二个一维数组的数组名和首地址,因此也是第二个一维数组的数组名和首地址,因此也为为1008。&a10是二维数组是二维数组a的的1行行0列元素地址,列元素地址,也是也是10

33、08。因此。因此a+1,a1,*(a+1),&a10是等同的。是等同的。 由此可得出:由此可得出:a+i,ai,*(a+i),&ai0是等同的。是等同的。 此外,此外,&ai和和ai也是相等的。因为在二维数组中也是相等的。因为在二维数组中不能把不能把&ai理解为元素理解为元素ai的地址,不存在元素的地址,不存在元素ai。语言规定,它是一种地址计算方法,表示数组语言规定,它是一种地址计算方法,表示数组a第第i行第行第0个元素的首地址。由此,我们得出:个元素的首地址。由此,我们得出:ai,&ai,*(a+i)和和a+i也都是相等的。也都是相等的。 另外,另外

34、,a0也可以看成是也可以看成是a0+0,是一维数组,是一维数组a0的的0号元素的首地址,而号元素的首地址,而a0+1则是则是a0的的1号元素号元素首地址,由此可得出首地址,由此可得出ai+j则是一维数组则是一维数组ai的的j号元号元素首地址,它等于素首地址,它等于&aij。 由由ai=*(a+i)得得ai+j=*(a+i)+j。由于。由于*(a+i)+j是二维是二维数组数组a的的i行行j列元素的首地址,所以,该元素的值等列元素的首地址,所以,该元素的值等于于*(*(a+i)+j)。定义int a34=1,3,5,7,;则二维数组a是由3个一维数组所组成的。设二维数组的首行的首地址为 ,

35、那么表表 示示 形形 式式含义含义地地 址址a a 二维数组名,指向一维数组二维数组名,指向一维数组a0a0,即,即0 0行首地行首地址址20002000a0a0, ,* *(a+0),(a+0),* *a a0 0行行0 0列元素地址列元素地址20002000a+1a+1,&a&a1 11 1行行首地址首地址20192019a a1 1, ,* *(a+1)(a+1)1 1行行0 0列元素列元素a10a10的地址的地址20192019a1+2,a1+2,* *(a+1)+2,(a+1)+2,&a12&a121 1行行2 2列元素列元素a12 a12 的地址的地

36、址20192019* *(a1+2),(a1+2),* *( (* *(a+1)+2),(a+1)+2),a12a121 1行行2 2列元素列元素a a1 12 2的值的值元素值为元素值为1313例例10.0 输出二维数组有关的值输出二维数组有关的值 #include define FROMAT,void main() int 341,3,5,7,9, ,; printf,*); printf,0 , *();printf,0,00);printf,1,);printf,10,*(+)+);printf,*();printf,); printf,*(*( ); 某一次运行结果如下:某一次运行结

37、果如下:, (0行首地址和行首地址和0行行0列元素地址列元素地址), (0行行0列元素地址列元素地址), (0行行0首地址和首地址和0行行0列元素地址列元素地址), (1行行0列元素地址和列元素地址和1行首地址行首地址), (1行行0列元素地址列元素地址), (2行行0列元素地址列元素地址), (2行首地址行首地址), (1行行0列元素的值列元素的值)2 . 2 . 指向多维数组元素的指针变量指向多维数组元素的指针变量(1) 指向数组元素的指针变量指向数组元素的指针变量例例10.11 10.11 用指针变量输出二维数组元素的值用指针变量输出二维数组元素的值 #include void main

38、() int 341,3,5,7,9,11,13,15,17,19,21,23; int*; for;) () printf(); printf(,*); 运行结果如下:运行结果如下:1 3 5 7 9 11 13 1519 21 23 把二维数组把二维数组a分解为一维数组分解为一维数组a0,a1,a2之后,设之后,设p为指向为指向二维数组的指针变量。可定义为:二维数组的指针变量。可定义为: int (*p)4 它表示它表示p是一个指针变量,它指向包含是一个指针变量,它指向包含4个元素的一维数组。个元素的一维数组。若指向第一个一维数组若指向第一个一维数组a0,其值等于,其值等于a,a0,或,或

39、&a00等。等。而而p+i则指向一维数组则指向一维数组ai。从前面的分析可得出。从前面的分析可得出*(p+i)+j是是二维数组二维数组i行行j 列的元素的地址,而列的元素的地址,而*(*(p+i)+j)则是则是i行行j列元素列元素的值。(指向数组元素的指针变量的值。(指向数组元素的指针变量p求求aij则需要用则需要用 i*m+j来求其位置。)来求其位置。) 二维数组指针变量说明的一般形式为:二维数组指针变量说明的一般形式为: 类型说明符类型说明符 (*指针变量名指针变量名)长度长度 其中其中“类型说明符为所指数组的数据类型。类型说明符为所指数组的数据类型。“*”表示其后表示其后的变量是

40、指针类型。的变量是指针类型。“长度表示二维数组分解为多个一维长度表示二维数组分解为多个一维数组时,一维数组的长度,也就是二维数组的列数。应注意数组时,一维数组的长度,也就是二维数组的列数。应注意“(*指针变量名指针变量名)”两边的括号不可少,如缺少括号则表示是两边的括号不可少,如缺少括号则表示是指针数组指针数组(本章后面介绍本章后面介绍),意义就完全不同了。,意义就完全不同了。 (2) 指向由个元素组成的一维数组的指针变量例例10.13 10.13 出二维数组任一行任一列元素的值出二维数组任一行任一列元素的值#include void main ( ) int 1,3,5,7,9,11, 13

41、,15,;int (*),; ;scanf( ,); printf(, ,*(*(); 运行情况如下:, (本行为键盘输入),3. 用指向数组的指针作函数参数用指向数组的指针作函数参数例10.13 有一个班,个学生,各学门课,计算总平均分数以及第个学生的成绩。这个题目是很简单的。只是为了说明用指向数组的指针作函数参数而举的例子。用函数average求总平均成绩,用函数search找出并输出第个学生的成绩。#include void main() void averagefloat *p,int n); void searchfloat (*p)4,int n); float score34=6

42、5,67,70,60,80, 87,90,81,90,99,100,98; average(*score,12);*求12个分数的平均分*searchscore,);*求序号为的学生的成绩*void averagefloat *,int ) float*_; float sum,aver; p_end; for(;_;) sumsum(*); aversum; printf(average,aver);void searchfloat (*)4,int ) / * p是指向具有4个元素的一维数组的指针 */int ; printf(the score of No. % are:,); for;

43、) printf(5.2,*(*(); 程序运行结果如下:程序运行结果如下:averageThe score of No.2 are:.例例10.4 在上题基础上,查找有一门以上课程不及格在上题基础上,查找有一门以上课程不及格的学生,打印出他们的全部课程的成绩。的学生,打印出他们的全部课程的成绩。 #include void main()void searchfloat (*p)4,int n);/*函数声明*/ float score34=65,57,70,60,58,87, 90,81,90,99,100,98; searchscore,);void searchfloat (*p)4,i

44、nt )int ,; for;) flag; for;) if(*(*())flag; if) printf(No.%d fails,his scores are:n,j+1); for;) printf(%.,*(*(); printf(); 程序运行结果如下:No.1 fails, his scores are:. . . .No.2 fails, his scores are:. . . . 10. 字符串与指针10.4.10.4.字符串的表示形式字符串的表示形式 (1) 用字符数组存放一个字符串,然后输出该字符串。用字符数组存放一个字符串,然后输出该字符串。例例 10.5 定义一个字符

45、数组,对它初始化,定义一个字符数组,对它初始化, 然后输出该字符串然后输出该字符串 #include void main()char stringI love China!; printf(,string); (2) 用字符指针指向一个字符串。用字符指针指向一个字符串。可以不定义字符数组,而定义一个字符指针。用字可以不定义字符数组,而定义一个字符指针。用字符指针指向字符串中的字符。符指针指向字符串中的字符。 例例106 定义字符指针定义字符指针#include void main()()char*string I love China!;printf(,);,); 字符串指针变量的定义说明与指

46、向字符变量的指针变量说明字符串指针变量的定义说明与指向字符变量的指针变量说明是相同的。只能按对指针变量的赋值不同来区别。对指向字是相同的。只能按对指针变量的赋值不同来区别。对指向字符变量的指针变量应赋予该字符变量的地址。符变量的指针变量应赋予该字符变量的地址。 如:如: char c,*p=&c; 表示表示p是一个指向字符变量是一个指向字符变量c的指针变量。的指针变量。 而:而: char *ps=C Language; 则表示则表示s是一个指向字符串的指针变量。把字符串的首地址是一个指向字符串的指针变量。把字符串的首地址赋予赋予s。 上例中,首先定义上例中,首先定义string是一个

47、字符指针变量,然后把字符是一个字符指针变量,然后把字符串的首地址赋予串的首地址赋予string(应写出整个字符串,以便编译系统把应写出整个字符串,以便编译系统把该串装入连续的一块内存单元该串装入连续的一块内存单元),并把首地址送入,并把首地址送入string。程。程序中的:序中的: char *ps=C Language; 等效于:等效于: char *ps; ps=C Language; 从以上两个例子中,可以看到:从以上两个例子中,可以看到: 1、字符数组和字符指针的概念不同。、字符数组和字符指针的概念不同。 2、字符指针指向字符串,而、字符指针指向字符串,而C语言中,字符串按数语言中,字

48、符串按数组方式处理,因而,字符数组和字符指针的访问方组方式处理,因而,字符数组和字符指针的访问方式相同。例如,均可以使用式相同。例如,均可以使用%s格式控制符进行整格式控制符进行整体输入输出。但应注意,如果不是字符数组,而是体输入输出。但应注意,如果不是字符数组,而是整型、实型等数字型数组,不能用整型、实型等数字型数组,不能用%s,只能逐个,只能逐个元素处理。元素处理。例例10.10.7 7 将字符串复制为字符串。将字符串复制为字符串。 #include void ()char am a boy,20; int ; for;*()!;) *()*(); *(); printf(string a

49、 is :,); printf(string b is:); for;!;) printf(,); printf(); 也可以设指针变量,用它的值的改变来指向字符串中的不同的字符。 例例10.8 用指针变量来处理例用指针变量来处理例107问题。问题。#include void main() char =I am a boy. ,20,*p1,*p2; int ; ; for(;*!;p1,p2)*;*;printf(string is:,); printf( :);for;!;) printf(,); printf();程序必须保证使和同步移动程序必须保证使和同步移动 10.4.2 10.4.

50、2 字符指针作函数参数字符指针作函数参数将一个字符串从一个函数传递到另一个函数,将一个字符串从一个函数传递到另一个函数,可以使用传地址的方式,即用字符数组名或字可以使用传地址的方式,即用字符数组名或字符指针变量作参数。有以下四种情况:符指针变量作参数。有以下四种情况: 实参实参 形参形参 数组名数组名 数组名数组名 数组名数组名 字符指针变量字符指针变量 字符指针变量字符指针变量 字符指针变量字符指针变量 字符指针变量字符指针变量 数组名数组名(1) 用字符数组作参数用字符数组作参数例例10.19 用函数调用实现字符串的复制用函数调用实现字符串的复制 #include void main()

51、void copy_stringchar from , char to ); char a = am a teacher; char =you are a student; printf(“string a= string , ,); printf(“copy string a to string b:n ”); copy_string (,); printf(nstring a=%snstring b=%sn,a,b); void copy_stringchar from , char to ) int ; whilefrom!)tofrom;to; 程序运行结果如下:程序运行结果如下: s

52、tring aI am a teacher string b you are a student copy string a to string b:string a I am a teacherstringI am a teacher(2) 形参用字符指针变量形参用字符指针变量 #include void main() void copy_stringchar * from, char *); char * am a teacher .; char *you are a student ; printf(string a=string ,); printf(copy string a to

53、string b:n ); _,);printf(nstring a=%snstring b=%sn,a,b); void copy_stringchar *,char *) for(;*from!;from,to)*to*from;*to; (3) (3) 对对copy string copy string 函数还可作简化函数还可作简化 1、将、将copy_string函数改写为函数改写为void copy_string (char *from,char *) while(*from)!)!) to;from; copy_string函数的函数体还可改为函数的函数体还可改为 while(*t

54、o*from)!)!);); copy_string函数的函数体还可写成函数的函数体还可写成 while(*from!)*to*from; *to; 上面的上面的while语句还可以进一步简化为下面的语句还可以进一步简化为下面的while语语句:句:while(*to*from););它与下面语句等价:它与下面语句等价:while(*to*from)!)!););将将*from赋给赋给*to,如果赋值后的,如果赋值后的*to值等于值等于则循则循环终止(环终止(已赋给已赋给*to) 函数体中函数体中while语句也可以改用语句也可以改用for语句:语句:for(;(;(*to*from)!;);

55、)!;);或或for(;(;*to*from;););也可用指针变量,函数也可用指针变量,函数copy_string可写为可写为void copy_string (char from ,char )char*,*; from;while(*p2*p1)!)!););10.4.3 10.4.3 对使用字符指针变量和字符数组的讨论对使用字符指针变量和字符数组的讨论字符数组和字符指针变量二者之间的区别:字符数组和字符指针变量二者之间的区别:(1) 字符数组由若干个元素组成,每个元素中放一个字符,而字符指针变量中存放的是地址字符串第1个字符的地址),决不是将字符串放到字符指针变量中。(2)赋值方式。对

56、字符数组只能对各个元素赋值,不 能用以下办法对字符数组赋值。 char str; strI love China!; 而对字符指针变量,可以采用下面方法赋值: char*; I love China!; (3)对字符指针变量赋初值: char * love China!;等价于 char*; I love Chian!; 而对数组的初始化: char str love China!; 不能等价于 char str; str I love China!;(4) 定义了一个字符数组,在编译时为它分配内存单元,它有确定的地址。而定义一个字符指针变量时,给指针变量分配内存单元,在其中可以放一个字符变量

57、的地址。 例如例如: char str: char str; scanfscanf(,strstr););(5) 指针变量的值是可以改变的,例如:例例10.0改变指针变量的值改变指针变量的值#include void ()char*I love China!; ; printf(,); 若定义了一个指针变量,并使它指向一个字符串,就可以用下标形式引用指针变量所指的字符串中的字符。例如: #include voidmain()char* love hina!; int ; printf ( “ The sixth character is %cn,a5); for;!;) printf(,);

58、10.10. 指向函数的指针指向函数的指针10.5.1 10.5.1 用函数指针变量调用函数用函数指针变量调用函数函数的指针:函数的入口地址函数的首地址)。函数的指针:函数的入口地址函数的首地址)。C语言规定语言规定函数的首地址就是函数名,所以函数名就是函数的指针。函数的首地址就是函数名,所以函数名就是函数的指针。指向函数的指针变量:存放函数入口地址函数指针的变指向函数的指针变量:存放函数入口地址函数指针的变量,称为指向函数的指针变量。简称函数的指针变量。量,称为指向函数的指针变量。简称函数的指针变量。函数可以通过函数名调用,也可以通过函数指针调用。函数可以通过函数名调用,也可以通过函数指针调

59、用。通过函数指针实现函数调用的步骤:通过函数指针实现函数调用的步骤:1、指向函数的指针变量的定义:、指向函数的指针变量的定义: 类型类型 (* 函数指针变量名)函数指针变量名)(); 例如例如 int (*p)(); 注意:两组括号()都不能少。注意:两组括号()都不能少。int表示被指表示被指向的函数的类型,即被指向的函数的返回值的类型。向的函数的类型,即被指向的函数的返回值的类型。2、指向函数的指针变量的赋值,指向某个函数:、指向函数的指针变量的赋值,指向某个函数: 函数指针变量名函数指针变量名=函数名;函数名;3、利用指向函数的指针变量调用函数:、利用指向函数的指针变量调用函数:(* 函

60、数指针变量名)(实参表)函数指针变量名)(实参表)例:输入例:输入10个数,求其中的最大值。个数,求其中的最大值。/* 使用函数名调用函数使用函数名调用函数 */main()int i,m,a10; for(i=0; i10; i+) scanf(%d,&ai); m=max(a); /* 函数调用格式:函数名函数调用格式:函数名(实参表实参表) */ printf(max=%dn,m); int max(int *p) /* max在在10个整数中选择最大值个整数中选择最大值 */ int i,t=*p; for(i=1; it)t=*(p+i); return t; 结果:结果: -52 87 29 79 -32 94 23 -112 46 67 max=94 声明函数声明函数 /* 使用函数指针变量调用函数使用函数指针变量调用函数 */ main() int i,m,a

温馨提示

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

评论

0/150

提交评论