《C语言课件教学PPT第10章指针》由会员分享,可在线阅读,更多相关《C语言课件教学PPT第10章指针(144页珍藏版)》请在金锄头文库上搜索。
1、第十章 主要内容主要内容 10.1地址和指针的概念地址和指针的概念10.变量的指针和指向变量的变量的指针和指向变量的指针变量指针变量10.数组与指针数组与指针10.字符串与指针字符串与指针10.指向函数的指针指向函数的指针10.返回指针值的函数返回指针值的函数10.指针数组和指向指针的指针指针数组和指向指针的指针10.8有关指针的数据类型和指针运算的小结有关指针的数据类型和指针运算的小结 10.1地址和指针的概念(1)计算机硬件系统的内存储器中,拥有大)计算机硬件系统的内存储器中,拥有大量的量的存储单元(容量为字节存储单元(容量为字节)。)。为了方便管理,必须为每一个存储单元编号,为了方便管理
2、,必须为每一个存储单元编号,这个编号就是存储单元的这个编号就是存储单元的“地址地址”。每个存储单。每个存储单元都有一个惟一的地址。元都有一个惟一的地址。1.内存地址内存地址内存中内存中存储单元的编号存储单元的编号(2)在地址所标识的存储单元中存放数据。)在地址所标识的存储单元中存放数据。注意:内存单元的注意:内存单元的地址地址与内存单元中的与内存单元中的数据数据是两个完全不同的概念。是两个完全不同的概念。2.变量地址变量地址系统分配给系统分配给变量的内存单元的变量的内存单元的起始地址起始地址假设有这样一个程序:假设有这样一个程序: main()intnum;scanf(%d,&num);pri
3、ntf(num=%dn,num);C编译程序编译到该变量定义语句时,编译程序编译到该变量定义语句时,将变量将变量num登录到登录到“符号表符号表”中。符号表的关键属性有两个:一是中。符号表的关键属性有两个:一是“标识符名标识符名(id)”,二是该标识符在内存空间中的,二是该标识符在内存空间中的“地址(地址(addr)”。为描述方便,假设系统分配给变量为描述方便,假设系统分配给变量num的的2字节存储单元为字节存储单元为2000和和2001,则起始地址,则起始地址2000就是变量就是变量num在内存中的地址。在内存中的地址。3.变量值的存取变量值的存取通过变量在内存中的地址进行通过变量在内存中的
4、地址进行系统执行系统执行“scanf(”%d“,&num);”和和“printf(”num=%dn“,num);”时,存取变量时,存取变量num值的方式值的方式可以有两种:可以有两种: (1)直接访问直接访问直接利用变量的地址进行存取直接利用变量的地址进行存取1)上例中上例中scanf(“%d”,&num)的执行过程是这的执行过程是这样的:样的:用变量名用变量名num作为索引值,检索符号表,作为索引值,检索符号表,找到找到变量变量num的起始地址的起始地址2000;然后将键盘输入的值;然后将键盘输入的值(假设为)送到内存单元(假设为)送到内存单元2000和和2001中。此时,中。此时,变量变量
5、num在内存中的地址和值在内存中的地址和值2)printf(num=%dn,num)的执行过程,的执行过程,与与scanf()很相似:很相似:首先找到变量首先找到变量num的起始地址的起始地址2000,然后从,然后从2000和和2001中取出其值,最后将它输出。中取出其值,最后将它输出。(2)间接访问间接访问通过通过另一变量访问该变量的值另一变量访问该变量的值语语言言规规定定:在在程程序序中中可可以以定定义义一一种种特特殊殊的的变变量量(称称为为指针变量指针变量),用来存放其它变量的),用来存放其它变量的地址地址。例例如如,假假设设定定义义了了这这样样一一个个指指针针变变量量num_point
6、er,它它被被分分配配到到4000、4001单单元元,其其值值可可通通过过赋赋值值语语句句“num_pointer=num;”得得到到。此此时时,指指针针变变量量num_pointer的的值值就就是是变变量量num在在内内存存中中的的起起始始地地址址2000.通通过过指指针针变变量量num_pointer存存取取变变量量num值值的的过过程程如如下:下:首首先先找找到到指指针针变变量量num_pointer的的地地址址(4000),取取出出其其值值2000(正正好好是是变变量量num的的起起始始地地址址);然然后从后从2000、2001中取出变量中取出变量num的值(的值(3)。)。在语言中,
7、指针是在语言中,指针是一种特殊的变量一种特殊的变量,它是,它是存放地址存放地址的。的。(3)两种访问方式的比较)两种访问方式的比较两两种种访访问问方方式式之之间间的的关关系系,可可以以用用某某人人甲甲(系系统)要找某人乙(变量)来类比。统)要找某人乙(变量)来类比。一一种种情情况况是是,甲甲知知道道乙乙在在何何处处,直直接接去去找找就就是是(即直接访问)。(即直接访问)。另另一一种种情情况况是是,甲甲不不知知道道乙乙在在哪哪,但但丙丙(指指针针变变量量)知知道道,此此时时甲甲可可以以这这么么做做:先先找找丙丙,从从丙丙处处获获得得乙乙的的去去向向,然然后后再再找找乙乙(即即间间接接访问)。访问
8、)。指针和指针变量的定义:指针和指针变量的定义:一个变量的地址称为该变量的“指针指针”。例如,地址2000是变量的指针。如果有一个变量专门用来存放另一变量的地址(即指针),则它称为“指针变量指针变量”。上述的i_pointer就是一个指针变量。为为表表示示指指针针变变量量和和它它指指向向的的变变量量之之间间的的关关系系,用用指指针针运运算算符符“*”表示。表示。例例如如,指指针针变变量量num_pointer与与它它所所指指向向的的变变量量num的的关关系系,表示为:表示为:*num_pointer,即,即*num_pointer等价于变量等价于变量num。因此,下面两个语句的因此,下面两个语
9、句的作用相同作用相同:num=3;/*将将3直接赋给变量直接赋给变量num*/num_pointer=#/*使使num_pointer指向指向num*/*num_pointer=3;/*将将3赋赋给给指指针针变变量量num_pointer所所指向的变量指向的变量*/ 10.2 变量的指针和指向变量的指 针变量10.10.1 .1 定义一个指针变量定义一个指针变量定义指针变量的一般形式为基类型基类型 *指针变量名;指针变量名;下面都是合法的定义:float *pointer_; char *pointer_; 可以用赋值语句使一个指针变量得到另一个变量的地址,从而使它指向一个该变量。例如
10、:例如:pointer_;pointer_;在定义指针变量时要注意两点:在定义指针变量时要注意两点:(1)指针变量前面的指针变量前面的“*”,表示该变量的类型为指针型,表示该变量的类型为指针型变量。变量。(2)例例: float *pointer_1;(3)指针变量名是指针变量名是pointer_1 ,而不是而不是* pointer_1 。 (4)(2) 在定义指针变量时必须指定在定义指针变量时必须指定基基类型。类型。(5)需要特别注意的是,只有整型变量的地址才能放到指需要特别注意的是,只有整型变量的地址才能放到指向整型变量的指针变量中。下面的赋值是错误的向整型变量的指针变量中。下面的赋值是错
11、误的 (6) float a; (7) int * pointer_1; (8) pointer_1=&a; 10.2.2 10.2.2 指针变量的引用指针变量的引用 注意注意:指针变量中只能存放地址(指针),不要将一个整数(或任何其他非地址类型的数据)赋给一个指针变量。 例例10. 通过指针变量访问整型变量通过指针变量访问整型变量#include voidmain ( ) int ,; int*pointer_, *pointer_; ; pointer_; /*把变量的地址赋给 pointer_1 */ pointer_; /*把变量的地址赋给 pointer_ */printf(%,%,
12、);printf(%,%,*pointer_, *pointer_); 对对“”和和“* *”运算符说明:运算符说明:如果已执行了语句 pointer_;(1)* pointer_的含义是什么?的含义是什么? “”和“*”两个运算符的优先级别相同,但按自右而左方向结合。因此,* pointer_与相同,即变量a的地址。 如果有pointer_2 * pointer_ ;它的作用是将(的地址)赋给pointer_2 ,如果pointer_2原来指向,经过重新赋值后它已不再指向了,而指向了。(2) *的含义是什么?的含义是什么? 先进行运算,得的地址,再进行*运算。*和*pointer_的作用是一
13、样的,它们都等价于变量。即*与等价。(3) (*pointer_)相当于。相当于。例例10 . 2 输入和两个整数,按先大后小的顺序输出输入和两个整数,按先大后小的顺序输出 和。和。#include void main() int *1,*2,*,; scanf(,);1; if();printf(=,=,); printf(max=,min=,*1,*2); 运行情况如下:运行情况如下:,当输入,时,由于,当输入,时,由于,将和交换。交换前的情况见图将和交换。交换前的情况见图(),交换后见图()。(),交换后见图()。注意:注意:此例中此例中a和和b并未交并未交换,而换,而p1和和p2的值改
14、变。的值改变。10.10.3 .3 指针变量作为函数参数指针变量作为函数参数例例10 . 3 对输入的两个整数按大小顺序输出对输入的两个整数按大小顺序输出 #include void main()void swap(int *,int *);int ,;int *pointer_,*pointer_; scanf(,);pointer_ ; pointer_2 ; if()swap( pointer_ , pointer_2 );printf(,); void swap(int *,int *) int temp; temp*1; *; *temp; 注意:注意:此例中此例中a和和b已经交换,
15、而已经交换,而pointer_ , pointer_2的值未改变。的值未改变。被调用函数不能改被调用函数不能改变实参指针变量的值,但可以改变它们所指变实参指针变量的值,但可以改变它们所指向的变量的值。向的变量的值。为为了了利利用用被被调调用用函函数数改改变变的的变变量量值值,应应该该使使用用指指针针(或或指指针针变变量量)作作函函数数实实参参。其其机机制制为为:在在执执行行被被调调用用函函数数时时,使使形形参参指指针针变变量量所所指指向向的的变变量量的的值值发发生生变变化化;函函数数调调用用结结束束后后,通通过过不不变变的的实实参参指指针针(或或实实参参指针变量)将变化的值保留下来。指针变量)
16、将变化的值保留下来。例例10. 输入、输入、 3个整数,按大小顺序输出。个整数,按大小顺序输出。#include void main() void exchange(int *1, int *2, int *3); int ,*,*,*; scanf(%,%,%,&, &, &); exchange (,); printf(,); void exchange(int *, int *, int *) void swap(int *, int *); if(*) swap(,); if(*) swap(,); if(* swap(,); void swap(int *, int *) int t
17、emp; temp*; *; *temp; 10.3 数组与指针 一个变量有地址,一个数组包含若干元素,每个数组元素都在内存中占用存储单元,它们都有相应的地址。指针变量既然可以指向变量,当然也可以指向数组元素(把某一元素的地址放到一个指针变量中)。所谓数组元素的指针就是数组元数组元素的指针就是数组元素的地址素的地址。 10.3.1 10.3.1 指向数组元素的指针指向数组元素的指针数组的指针数组的指针数组在内存中的数组在内存中的起始地址起始地址,数组元数组元素素的指针的指针数组元素在内存中的起始地址。数组元素在内存中的起始地址。2.指向数组的指针变量的定义指向数组的指针变量的定义指向数组的指针
18、变量的定义,与指向普通变量的指向数组的指针变量的定义,与指向普通变量的指针变量的定义方法一样。指针变量的定义方法一样。例如:例如: ; ( (定义为包含个整型数据的数组定义为包含个整型数据的数组) )* *; ( (定义为指向整型变量的指针变量定义为指向整型变量的指针变量) )应当注意,如果数组为型,则指针变量的基类型亦应当注意,如果数组为型,则指针变量的基类型亦应为型。应为型。 对该指针变量赋值:对该指针变量赋值:;把元素的地址赋给指针变量。也就是使指向数组的第号元素,如图:在在C中中,数组名代表数组的首地址。因此数组名代表数组的首地址。因此p=a;与与p=&a0;是等价的。是等价的。p=a
19、;是将是将a数组的首地址赋给指针变量数组的首地址赋给指针变量p。但这里的。但这里的a并不代表整个数组。并不代表整个数组。上面定义可写成上面定义可写成:int*p=a;作用是把作用是把a数组首元素地址赋给指针变量数组首元素地址赋给指针变量p(不是(不是*p)10.10. .通过指针引用数组元素通过指针引用数组元素若若p=a;是将整型数组是将整型数组a的首地址赋给整型指针变量的首地址赋给整型指针变量p,则则*p=5;是将整数是将整数5赋给赋给a数组的第一个元素数组的第一个元素a0,等价于等价于a0=5。p+1表示指针变量表示指针变量p当前所指的数组元素的当前所指的数组元素的下一个元素下一个元素。但
20、。但p+1不是不是p的值加的值加1。若有。若有p=&a0;则则p+i(或或a+i)就是就是ai的地址的地址(因为因为a代表数组代表数组a的首地址的首地址)。若有若有p=&a0;则则*(p+i)或或*(a+i)就是就是p+i或或a+i所指向的数组元素,所指向的数组元素,即即ai。也就是说也就是说*(p+i)=*(a+i)=ai。指向数组的指针变量可以带下标,如:指向数组的指针变量可以带下标,如:pi与与*(p+i)是等价的。是等价的。引用一个数组元素,可以用:()() 下标法,如形式;下标法,如形式;()() 指针法,如指针法,如*()或()或*()()。其中是数组名,是指向数组元素的指针变量,
21、其初值。例例10.5 输出数组中的全部元素。输出数组中的全部元素。 假设有一个数组,整型,有个元素。要输出各元素的值有三种方法: (1)下标法。#include void main() int ; int;for(;)scanf(,); printf();for(;)printf(,); (2) 通过数组名计算数组元素地址,找出元素的值。#include voidmain() int ; int ;for(; )scanf(,);printf(); for(;) printf(,*(); (3) 用指针变量指向数组元素。#include void main() int ; int *,; fo
22、r(;) scanf(,); printf(); for(;();) printf( ,*); 这三种方法比较这三种方法比较:1.前两种效率相同,每次都要计算前两种效率相同,每次都要计算元素地址元素地址,费时较多。费时较多。2.第三种方法用指针变量第三种方法用指针变量直指元素直指元素,不必每,不必每次从新计算地址,像次从新计算地址,像P+这样的运算速度很这样的运算速度很快,所以能大量提高执行效率。快,所以能大量提高执行效率。3.下标法下标法比较直观比较直观,能直接知道是第几个元,能直接知道是第几个元素,地址法或指针法不直观,需要仔细分析素,地址法或指针法不直观,需要仔细分析地址和指针的指向。地
23、址和指针的指向。几个注意的问题:指针变量可以实现本身的值的改变。如p+是合法的;而a+是错误的。因为a是数组名,它是数组的首地址,是常量。要注意指针变量的当前值。请看下面的程序:例例10. 通过指针变量输出数组的个元素。通过指针变量输出数组的个元素。 #include void main() int*,;for(; )scanf(,); printf(); for(;, ) printf(,*);程序运行情况:程序运行情况:1 2 3 4 5 6 7 8 9 022153 234 0 0 30036 25202 11631 8259 8237 28483显然输出的数值并不是数组中各元素的值显然
24、输出的数值并不是数组中各元素的值 #include void main() int*,;for(;)scanf(,); printg(); p=a; for(;, ) printf(,*);从上例可以看出,虽然定义数组时指定它包含从上例可以看出,虽然定义数组时指定它包含10个元素,但指针变量可以指到数组以后的内存单个元素,但指针变量可以指到数组以后的内存单元,系统并不认为非法。元,系统并不认为非法。*p+,由于,由于+和和*同优先级,结合方向自同优先级,结合方向自右而左,右而左,等价于等价于*(p+)。*(p+)与与*(+p)作用不同。若作用不同。若p的初值为的初值为a,则,则*(p+)等价等
25、价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() i(int arr,int ); int array; (array,); void (int arr,int ) array为实参数组名,arr为形参数组名。在学习指针变量之
26、后就更容易理解这个问题了。数组名就是数组的首地址,实参向形参传送数组名实际上就是传送数组的地址,形参得到该地址后也指向同一数组。这就好象同一件物品有两个彼此不同的名称一样。 同样,指针变量的值也 是地址,数组指针变量 的值即为数组的首地址 ,当然也可作为函数的 参数使用。例例10 将数组中个整数按相反顺序存放。将数组中个整数按相反顺序存放。#include void main() void inv(int ,int ); int , ,;printf(The original array:);for(;)printf (,);printf(); inv (,); printf(The arra
27、y has been in verted:); for(;) printf (,); printf ();void inv(int ,int ) /*形参x是数组名*/ int temp,();for(;) ;temp; ; temp; return; 运行情况如下:运行情况如下:The original array:,The array has been inverted:,如果有一个实参数组,想在函数中改变此数如果有一个实参数组,想在函数中改变此数组中的元素的值,实参与形参的对应关系有组中的元素的值,实参与形参的对应关系有以下种情况:以下种情况: (1) 形参和实参都用数组名,如:形参和实
28、参都用数组名,如:void main() void (int ,int ) int ; (,); (2) 实参用数组名,形参用指针变量。如:实参用数组名,形参用指针变量。如:void () void (int *,int )int ; (,); (3)实参形参都用指针变量。例如:实参形参都用指针变量。例如:void main() void (int *,int )int , *p=a; (p,); (4) 实参为指针变量,形参为数组名。如:实参为指针变量,形参为数组名。如: void main() void (int x ,int ) ,*p=a; (p,); #include void ma
29、in() void inv(int *,int ); int ,*; printf(The original array:n ); for(;,)scanf(,);printf(); ; inv(,); /* 实参为指针变量实参为指针变量 ,一定一定 要有确定值要有确定值*/ printf(The array has been inverted :); for(; ) printf(,*); printf(); void inv(int *,int )int,temp,*,*;(); ;for(;,)emp*;*;*temp;return; 例例109 用选择法对个整数按由大到小顺序排序。用选
30、择法对个整数按由大到小顺序排序。 #include void main() void sort(int ,int ); int*,10; ; for(;) scanf(,); ; sort(,); for(,;)(,*);void sort(int ,int )/*把x改为*x,下面不 int ,; 变,程序依然合法*/ for(;);for(;)() ; (!); ; ; 10.3.4 10.3.4 多维数组与指针多维数组与指针 用指针变量可以指向一维数组中的元素,也可以指向多维数组中的元素。但在概念上和使用上,多维数组的指针比一维数组的指针要复杂一些。 1. 1. 多维数组元素的地址多维数
31、组元素的地址先回顾一下多维数组的性质,可以认为二维数组是“数组的数组”,例 :定义定义int a34=0,1,2,3,4,5,6,7,8,9,10,11则二维数组a是由3个一维数组所组成的。设二维数组的首行的首地址为1 ,则各下标变量的首地址及其值如图所示。各下标变量的首地址及其值如图所示。语言允许把一个二维数语言允许把一个二维数组分解为多个一维数组来组分解为多个一维数组来处理。因此数组处理。因此数组a可分解为三个一维数组,即可分解为三个一维数组,即a0,a1,a2。每一个一维数组又含有四个元素。每一个一维数组又含有四个元素。数组及数组元素的地址表示如下:数组及数组元素的地址表示如下:从二维数
32、组的角度来看,从二维数组的角度来看,a是二维数组名是二维数组名,a代表整代表整个二维数组的首地址,个二维数组的首地址,也是也是二维数组二维数组0行的首地址,行的首地址,等于等于1000。a+1代表第一行的首地址,等于代表第一行的首地址,等于1008。如图:如图:a0是第一个是第一个一维数组的数组名和首地址一维数组的数组名和首地址,因此也,因此也为为1000。*(a+0)或或*a是与是与a0等效等效的,的,它表示一维它表示一维数组数组a00号元素的首地址,也为号元素的首地址,也为1000。&a00是二维数组是二维数组a的的0行行0列元素首地址,同样是列元素首地址,同样是1000。因此,因此,a,
33、a0,*(a+0),*a,&a00是相等的是相等的。同理,同理,a+1是二维数组是二维数组1行的首地址,等于行的首地址,等于1008。a1是第二个一维数组的数组名和首地址,因此也是第二个一维数组的数组名和首地址,因此也为为1008。&a10是二维数组是二维数组a的的1行行0列元素地址,列元素地址,也是也是1008。因此。因此a+1,a1,*(a+1),&a10是等同的。是等同的。由此可得出:由此可得出:a+i,ai,*(a+i),&ai0是是等同等同的。的。此外,此外,&ai和和ai也是相等也是相等的。因为在二维数组中的。因为在二维数组中不能把不能把&ai理解为元素理解为元素ai的地址,不存在
34、元素的地址,不存在元素ai。语言规定,它是一种语言规定,它是一种地址计算方法地址计算方法,表示数组,表示数组a第第i行第行第0个元素的首地址。由此,我们得出:个元素的首地址。由此,我们得出:ai,&ai,*(a+i)和和a+i也都是相等的。也都是相等的。另外,另外,a0也可以看成是也可以看成是a0+0,是一维数组,是一维数组a0的的0号元素的首地址,而号元素的首地址,而a0+1则是则是a0的的1号元素首号元素首地址,由此可得出地址,由此可得出ai+j则是一维数组则是一维数组ai的的j号元素号元素首地址,它等于首地址,它等于&aij。由由ai=*(a+i)得得ai+j=*(a+i)+j。由于。由
35、于*(a+i)+j是二维数组是二维数组a的的i行行j列元素的首地址,列元素的首地址,所以,该元素的值等于所以,该元素的值等于*(*(a+i)+j)。定义int a34=1,3,5,7,;则二维数组a是由3个一维数组所组成的。设二维数组的首行的首地址为 ,则表表 示示 形形 式式含义含义地地 址址a a 二维数组名,指向一维数组二维数组名,指向一维数组a0a0,即,即0 0行首行首地址地址20002000a0a0, ,*(a+0),*(a+0),*a*a0 0行行0 0列元素地址列元素地址20002000a+1a+1,&a&a1 11 1行行首地址首地址20082008a a1 1,*(a+1)
36、,*(a+1)1 1行行0 0列元素列元素a10a10的地址的地址20082008a1+2,a1+2,*(a+1)+2,*(a+1)+2,&a12&a121 1行行2 2列元素列元素a12 a12 的地址的地址20122012*(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(
37、,0 , *();printf(,0,00);printf(,1,);printf(,10,*(+)+);printf(,*();printf(,); printf(,*(*( ); 某一次运行结果如下:某一次运行结果如下:, (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 用指
38、针变量输出二维数组元素的值用指针变量输出二维数组元素的值 #include void main() 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个元素的一维数组。个元素的
39、一维数组。若指向第一个一维数组若指向第一个一维数组a0,其值等于,其值等于a,a0,或,或&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 出二维数组任一行任一列元素的值出二维
41、数组任一行任一列元素的值#include void main ( ) int 1,3,5,7,9,11, 13,15,;int (*),; ;scanf( ,); printf(, ,*(*(); 运行情况如下:,(本行为键盘输入),3. 用指向数组的指针作函数参数用指向数组的指针作函数参数例10.13 有一个班,个学生,各学门课,计算总平均分数以及第个学生的成绩。这个题目是很简单的。只是为了说明用指向数组的指针作函数参数而举的例子。用函数average求总平均成绩,用函数search找出并输出第个学生的成绩。#include void main() void average(float *p
42、,int n); void search(float (*p)4,int n); float score34=65,67,70,60,80, 87,90,81,90,99,100,98; average(*score,12);*求12个分数的平均分*search(score,);*求序号为的学生的成绩*void average(float *,int ) float*_; float sum,aver; p_end; for(;_;) sumsum(*); aversum; printf(average,aver);void search(float (*)4,int ) / * p是指向具有
43、4个元素的一维数组的指针 */int ; printf(the score of No. % are:,); for(;) printf(5.2,*(*(); 程序运行结果如下:程序运行结果如下:averageThe score of No.2 are:.例例10.4 在上题基础上,查找有一门以上课程不及格的在上题基础上,查找有一门以上课程不及格的学生,打印出他们的全部课程的成绩。学生,打印出他们的全部课程的成绩。 #include void main()void search(float (*p)4,int n);/*函数声明*/ float score34=65,57,70,60,58,8
44、7, 90,81,90,99,100,98; search(score,);void search(float (*p)4,int )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.字符串的表示形式字符串的
45、表示形式 (1) 用字符数组存放一个字符串,然后输出该字符串。用字符数组存放一个字符串,然后输出该字符串。例例 10.5 定义一个字符数组,对它初始化,定义一个字符数组,对它初始化, 然后输出该字符串然后输出该字符串 #include void main()char stringI love China!; printf(,string); (2) 用字符指针指向一个字符串。用字符指针指向一个字符串。可以不定义字符数组,而定义一个字符指针。用字符指针指向字符串中的字符。 例例106 定义字符指针定义字符指针#include void main()char*string I love China
46、!;printf(,);字符字符串串指针变量的定义说明与指向字符指针变量的定义说明与指向字符变量变量的指针变量说明的指针变量说明是相同的。只能按对指针变量的赋值不同来区别。对指向字是相同的。只能按对指针变量的赋值不同来区别。对指向字符变量的指针变量应赋予该字符变量的地址。符变量的指针变量应赋予该字符变量的地址。如:如:charc,*p=&c;表示表示p是一个指向字符变量是一个指向字符变量c的指针变量。的指针变量。而:而:char*ps=CLanguage;则表示则表示s是一个指向字符串的指针变量。把字符串的首地址是一个指向字符串的指针变量。把字符串的首地址赋予赋予s。上例中,首先定义上例中,首
47、先定义string是一个字符指针变量,然后把字符是一个字符指针变量,然后把字符串的首地址赋予串的首地址赋予string(应写出整个字符串,以便编译系统把应写出整个字符串,以便编译系统把该串装入连续的一块内存单元该串装入连续的一块内存单元),并把首地址送入,并把首地址送入string。程。程序中的:序中的:char*ps=CLanguage;等效于:等效于:char*ps;ps=CLanguage;从以上两个例子中,可以看到:从以上两个例子中,可以看到:1、字符数、字符数组和字符指和字符指针的概念不同。的概念不同。2、字符指、字符指针指向字符串,而指向字符串,而C语言中,字符串按数言中,字符串按
48、数组方式方式处理,因此,字符数理,因此,字符数组和字符指和字符指针的的访问方式方式相同。例如,均可以使用相同。例如,均可以使用%s格式控制符格式控制符进行整体行整体输入入输出。但出。但应注意,注意,如果不是字符数如果不是字符数组,而是整型、,而是整型、实型等数字型数型等数字型数组,不能用,不能用%s,只能逐个元素只能逐个元素处理。理。例例10.10.7 7 将字符串复制为字符串。将字符串复制为字符串。 #include void ()char am a boy,20; int ; for(;*()!;) *()*(); *(); printf(string a is :,); printf(s
49、tring 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.2 字符指针作函数参数字符指针
50、作函数参数将一个字符串从一个函数传递到另一个函数,将一个字符串从一个函数传递到另一个函数,可以使用传地址的方式,即用字符数组名或字可以使用传地址的方式,即用字符数组名或字符指针变量作参数。有以下符指针变量作参数。有以下四种情况:四种情况:实参实参形参形参数组名数组名数组名数组名数组名数组名字符指针变量字符指针变量字符指针变量字符指针变量字符指针变量字符指针变量字符指针变量字符指针变量数组名数组名(1) 用字符数组作参用字符数组作参数数例例10.19 用函数调用实现字符串的复制用函数调用实现字符串的复制 #include void main() void copy_string(char fro
51、m , 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_string(char from , char to ) int ; while(from!)tofrom;to; 程序运行结果如下程序运行结果如下: string aI am a teacher s
52、tring 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_string(char * from, char *); char * am a teacher .; char *you are a student ; printf(string a=string ,); printf(copy string a to string b:n ); _(,);pri
53、ntf(nstring a=%snstring b=%sn,a,b); void copy_string(char *,char *) for(;*from!;from,to)*to*from;*to; (3) (3) 对对copy string 函数还可作简化函数还可作简化 1、将、将copy_string函数改写为函数改写为void copy_string (char *from,char *) while(*from)!) to;from; copy_string函数的函数体还可改为函数的函数体还可改为 while(*to*from)!); copy_string函数的函数体还可写成函数
54、的函数体还可写成 while(*from!)*to*from; *to; 上面的上面的while语句还可以进一步简化为下面的语句还可以进一步简化为下面的while语语句:句:while(*to*from);它与下面语句等价:while(*to*from)!);将*from赋给*to,如果赋值后的*to值等于则循环终止(已赋给*to) 函数体中函数体中while语句也可以改用语句也可以改用for语句:语句:for(;(*to*from)!;);或for(;*to*from;);也可用指针变量,函数也可用指针变量,函数copy_string可写为可写为void copy_string (char
55、from ,char )char*,*; from;while(*p2*p1)!);10.4.3 10.4.3 对使用字符指针变量和字符数组的讨论对使用字符指针变量和字符数组的讨论字符数组和字符指针变量二者之间的区别:字符数组和字符指针变量二者之间的区别:(1) 字符数组由若干个元素组成,每个元素中放一个字符,而字符指针变量中存放的是地址(字符串第1个字符的地址),决不是将字符串放到字符指针变量中。(2)赋值方式。对字符数组只能对各个元素赋值,不 能用以下办法对字符数组赋值。 char str; strI love China!; 而对字符指针变量,可以采用下面方法赋值: char*; I l
56、ove China!; (3)对字符指针变量赋初值: char * love China!;等价于 char*; I love Chian!; 而对数组的初始化: char str love China!; 不能等价于 char str; str I love China!;(4) 定义了一个字符数组,在编译时为它分配内存单元,它有确定的地址。而定义一个字符指针变量时,给指针变量分配内存单元,在其中可以放一个字符变量的地址。 例如例如: : char str; scanf(,str););(5) 指针变量的值是可以改变的,例如:例例10.0改变指针变量的值改变指针变量的值#include vo
57、id ()char*I love China!; ; printf(,); 若定义了一个指针变量,并使它指向一个字符串,就可以用下标形式引用指针变量所指的字符串中的字符。例如例如: #include voidmain()char* love hina!; int ; printf ( “ The sixth character is %cn,a5); for(;!;) printf(,); 10.10. 指向函数的指针指向函数的指针10.5.1 10.5.1 用函数指针变量调用函数用函数指针变量调用函数函数的指针函数的指针:函数的:函数的入口地址入口地址(函数的首地址)。(函数的首地址)。C语
58、言规定语言规定函数的首地址就是函数名,所以函数的首地址就是函数名,所以函数名就是函数的指针。函数名就是函数的指针。指向函数的指针变量:指向函数的指针变量:存放函数入口地址(函数指针)的变存放函数入口地址(函数指针)的变量,称为指向函数的指针变量。简称函数的指针变量。量,称为指向函数的指针变量。简称函数的指针变量。函数可以通过函数名调用,也可以通过函数指针调用。函数可以通过函数名调用,也可以通过函数指针调用。通过函数指针实现函数调用的步骤:通过函数指针实现函数调用的步骤:1、指向函数的指针变量的定义:、指向函数的指针变量的定义:类型类型(*函数指针变量名)函数指针变量名)();例如例如int(*
59、p)();注意注意:两组括号()都不能少。:两组括号()都不能少。int表示被表示被指向的函数的类型,即被指向的函数的返回值的类型。指向的函数的类型,即被指向的函数的返回值的类型。2、指向函数的指针变量的赋值,指向某个函数:、指向函数的指针变量的赋值,指向某个函数:函数指针变量名函数指针变量名=函数名;函数名;3、利用指向函数的指针变量调用函数:、利用指向函数的指针变量调用函数:(*函数指针变量名)(实参表)函数指针变量名)(实参表)例:输入例:输入10个数,求其中的最大值。个数,求其中的最大值。/*使用函数名调用函数使用函数名调用函数*/main()inti,m,a10;for(i=0;i1
60、0;i+)scanf(%d,&ai);m=max(a);/*函数调用格式:函数名函数调用格式:函数名(实参表实参表)*/printf(max=%dn,m);intmax(int*p)/*max在在10个整数中选择最大值个整数中选择最大值*/inti,t=*p;for(i=1;it)t=*(p+i);returnt;结果:结果:-52872979-329423-1124667max=94声明函数声明函数/*使用函数指针变量调用函数使用函数指针变量调用函数*/main()int i,m,a10,max(int *); /* declare func */ int (*pf)(); /* defin
61、e func pointer */for(i=0; imax() */ m=(*pf)(a); /* call max */ printf(max=%dn,m);声声明明函数函数指针的定义:指针的定义:定义函数指针变量定义函数指针变量pfpf( (返回整型数返回整型数) )指针的初始化:指针的初始化:函函数数指指针针pfpf指指向向maxmax指针的引用:指针的引用:调用函数指针调用函数指针pfpf指向的函数指向的函数maxmaxintint max(intmax(int *p) *p) intint i,ti,t=*p;=*p; for(ifor(i=1; i10; i+)=1; i)t)t
62、t)t=*(=*(p+ip+i);); return t; return t;说明:说明:(1 1)定定义义函函数数指指针针变变量量时时,两两组组括括号号()都都不不能能少少。如如果果少少了了前前面面的的一一组组括括号号=返返回回值值类类型型 * * 函函数数名名()();- -返返回回值值为为地址值(指针)的函数。地址值(指针)的函数。(2 2)函函数数指指针针变变量量的的类类型型是是被被指指向向的的函函数数的的类类型型,即即返返回回值类型。值类型。(3 3)函函数数指指针针的的赋赋值值,只只要要给给出出函函数数名名,不不必必给给出出参参数数。(不要给出实参或形参)。(不要给出实参或形参)。
63、(4 4)用用指指针针变变量量调调用用函函数数时时,(* (* 函函数数指指针针) )代代替替函函数数名名。参数表与使用函数名调用函数一样。参数表与使用函数名调用函数一样。(5 5)可可以以看看出出,定定义义的的函函数数指指针针变变量量可可以以用用于于一一类类函函数数,只只要要这这些些函函数数返返回回值值类类型型(函数类型)相同。(函数类型)相同。函函数数可可以以通通过过函函数数名名调调用用,也也可可以以通通过过函函数数指指针针调调用用。函函数数指指针针常常常常用用在在函函数数需需要要作为函数参数的情况。作为函数参数的情况。10.5.2 10.5.2 用指向函数的指针作函数参数用指向函数的指针
64、作函数参数 函数指针变量常用的用途之一是把指针作为参数传递到其他函数。指向函数的指针也可以作为参数,以实现函数地址的传递,这样就能够在被调用的函数中使用实参函数。函函数数的的参参数数除除了了可可以以是是变变量量、指指向向变变量量的的指指针针,数数组组(实实际际是是指指向向数数组组的的指指针针)、指指向向数组的指针以外,数组的指针以外,还可以是函数的指针。还可以是函数的指针。函函数数的的指指针针可可以以作作为为函函数数参参数数,在在函函数数调调用用时时可可以以将将某某个个函函数数的的首首地地址址传传递递给给被被调调用用的的函函数数,使使这这个个被被传传递递的的函函数数在在被被调调用用的的函函数数
65、中中调调用用(看看上上去去好好象象是是将将函函数数传传递递给给一一个个函函数数)。函函数数指指针针的的使使用用在在有有些些情情况况下下可可以以增增加加函函数数的的通通用用性性,特特别别是是在在可可能能调调用用的的函函数数可变的情况下。可变的情况下。 实参函数名 f1 void (int (*x1)(int),int (*x2)(int,int)) int ,; (*)(); *调用函数* (*)(,);*调用函数* 例例10.10.3 3 设一个函数设一个函数processprocess,在调用它的时候,每次在调用它的时候,每次实现不同的功能。输入和两个数,第一次调用实现不同的功能。输入和两个
66、数,第一次调用processprocess时找出和中大者,第二次找出其中小者,时找出和中大者,第二次找出其中小者,第三次求与之和。第三次求与之和。 #include void main() int max(int,int); /* 函数声明 */ int min(int,int); /* 函数声明 */ int add(int,int); /* 函数声明 */ void process (int , int , int(*fun)(); /* 函数声明 */ int ,; printf(enter a and b:); scanf(,);printf(max); process(,);prin
67、tf(min);process(,);printf(sum);process(,);int max(int ,int ) /* 函数定义 */int ; if(); else ; return();int min(int ,int ) /* 函数定义 */ int ; if();else ;return(); int (int ,int ) /* 函数定义 */ int; ; return();void process(int ,int ,int (*fun)(int,int) int result; result(*fun)(,); printf(, result);(1)函数)函数proc
68、ess处理两个整数数,并输出一个值。同时处理两个整数数,并输出一个值。同时又要求又要求process具有具有通用处理能力通用处理能力(处理求大数、小数、(处理求大数、小数、和),所以可以考虑在调用和),所以可以考虑在调用process时将相应的处理方法时将相应的处理方法(“处理函数处理函数”)传递给)传递给process。(2)process函数要接受函数作为参数,即函数要接受函数作为参数,即process应该应该有一个有一个函数指针作为形式参数函数指针作为形式参数,以接受函数的地址。这样,以接受函数的地址。这样process函数的函数原型应该是:函数的函数原型应该是:intprocess(i
69、ntx,inty,int(*f)();(3)“函数指针作为函数参数函数指针作为函数参数”的使用与前面介绍的步的使用与前面介绍的步骤完全相同,即骤完全相同,即函数指针变量的定义函数指针变量的定义-在通用函数在通用函数process的形参定义部分实现;的形参定义部分实现;函数指针变量的赋值函数指针变量的赋值-在通用函数在通用函数的调用的虚实结合时实现;的调用的虚实结合时实现;用函数指针调用函数用函数指针调用函数-在通用在通用函数内部实现。函数内部实现。(4)main函数调用通用函数函数调用通用函数process处理计算两数中大处理计算两数中大数的过程是这样的:数的过程是这样的:l将将函函数数名名m
70、axmax(实实际际是是函函数数maxmax的的地地址址)连连同同要要处处理理的的两两个个整整数数a,ba,b一一起起作作为为processprocess函函数数的的实实参参,调调用用processprocess函数。函数。l lprocessprocess函函数数接接受受来来自自主主调调函函数数mainmain传传递递过过来来的的参参数数,包包括括两两个个整整数数和和函函数数maxmax的的地地址址,函函数数指指针针变变量量funfun获得了函数获得了函数maxmax的地址的地址。l l在在processprocess函函数数的的适适当当位位置置调调用用函函数数指指针针变变量量funfun指
71、指向向的的函函数数,即即调调用用maxmax函函数数。这这样样调调用用点点就就获获得得了了两两数大数的结果,由数大数的结果,由printfprintf函数输出结果。函数输出结果。 同同样样,mainmain函函数数调调用用通通用用函函数数processprocess处处理理计计算算两数小数、和的过程基本一样。两数小数、和的过程基本一样。(5 5)processprocess函函数数头头部部:函函数数指指针针定定义义中中不不需需要要指指定定形形参参个个数数。但但是是一一般般情情况况函函数数指指针针指指向向的的函函数数参参数数个个数数一一般般是是数数量量类类型型相相同同的的,以以便便用用统统一一的
72、的格格式式如如(*(*f)(x,yf)(x,y) )去去调用。调用。processprocess函函数数是是一一个个“通通用用”整整数数处处理理函函数数,它它使使用用函函数数指指针针作作为为其其中中的的一一个个参参数数,以以实现同一个函数中调用不同的处理函数实现同一个函数中调用不同的处理函数。10.10. 返回指针值的函数返回指针值的函数一个函数可以带回一个整型值、字符值、实型值等,也可以带回指针型的数据,即地址。其概念与以前类似,只是带回的值的类型是指针类型而已。这种带回指针值的函数,一般定义形式为类型名类型名 *函数名(参数表列)函数名(参数表列);例如:int *(int ,int );
73、例:返回两个数中大数地址的函数。例:返回两个数中大数地址的函数。int*fun(int,int);main()inti,j,*p;printf(entertwonumtoi,j:);scanf(%d%d,&i,&j);p=fun(i,j);/*调用调用fun,返回大数地址,赋值给指针,返回大数地址,赋值给指针变量变量p*/printf(max=%dn,*p);/*打印打印p指向的数据指向的数据*/int*fun(intx,inty)/*fun函数返回形参函数返回形参x,y中较大数的地址中较大数的地址(指针)(指针)*/int*z;if(xy)z=&x;elsez=&y;returnz;结果:结
74、果:entertwonumtoi,j:1238max=38说明:说明:(1)main函数从键盘获得两个整数函数从键盘获得两个整数i,j(本例(本例12,38)。将)。将i,j作为实参调用作为实参调用fun。(2)通过虚实结合,)通过虚实结合,fun函数的形参函数的形参x,y获得了这两个整数获得了这两个整数(本例(本例12,38),),将大数的地址返回(本例是将大数的地址返回(本例是&y)。)。(3)返回的)返回的地址值地址值赋值给赋值给main函数的函数的指针变量指针变量p,main函数函数打印打印p指向的整型数,即指向的整型数,即y的值。的值。例例10104 4 有若干个学生的成绩(每个学生
75、有门课程有若干个学生的成绩(每个学生有门课程),要求在用户输入学生序号以后,能输出该学生的全),要求在用户输入学生序号以后,能输出该学生的全部成绩。用指针函数来实现。部成绩。用指针函数来实现。 #include void main()float *score 4=60,70,80,90, 56,89,67,88,34,78,90,66; float*search(float (*pointer)4,int n); float*; int ,; printf(enter the number of student:); scanf(,); printf(The scores of No are:
76、,); search(,);for(;printf(,*(); float * search(float (*)4,int ) float *; *(); return(); 运行情况如下:运行情况如下:enter the number of student:The scores of No. are:56.00 89.00 67.00 88.00例例10.5 对上例中的学生,找出其中有不及格课对上例中的学生,找出其中有不及格课程的学生及其学生号。程的学生及其学生号。#include void main()float score 4=60,70,80,90,56, 89,67,88,34,78
77、,90,66; float search(float (*pointer)4); float*; i ,; for(;)search(score );(*(score)printf(scores:,); for(;) printf(5.2,*(); printf(); float * search(float (*)4) float *; *(1); for(i=0;i4;i+) if(*(*pointer+i)60)pt=*pointer; return(); 10.7 10.7 指针数组和指向指针的指针指针数组和指向指针的指针10.7.1 10.7.1 指针数组的概念指针数组的概念一个数组
78、,若其元素均为指针类型数据,称为指针指针数组数组,也就是说,指针数组中的每一个元素都相当于一个指针变量。一维指针数组的定义形式为一维指针数组的定义形式为: :类型名类型名*数组名数组长度;数组名数组长度;例如:例如:*;定定义义一一个个4 4个个元元素素的的数数组组p p,其其中中每每个个元元素素是是一一个个整整型指针,也即数组型指针,也即数组p p是一个是一个4 4元素整型指针数组元素整型指针数组。又如:又如:char *p4;char *p4;定定义义一一个个4 4个个元元素素的的字字符符指指针针数数组组p p,其其中中每每个个数数组组元元素素是是一一个个字字符符指指针针,可可以以指指向向
79、一一个个字字符符串串。也也就就是说利用此字符指针数组可以指向是说利用此字符指针数组可以指向4 4个字符串。个字符串。指指针针数数组组用用得得最最多多的的是是“字字符符型型指指针针数数组组”,利利用用字字符符指指针针数数组组可可以以指指向向多多个个长长度度不不等等的的字字符符串串,使使字符串处理字符串处理更加方便、灵活,节省内存空间更加方便、灵活,节省内存空间。使用字符型指针数组指向多个字符串使用字符型指针数组指向多个字符串(上页(上页下图)下图)使使用用字字符符型型指指针针数数组组指指向向多多个个字字符符串串与与使使用用两维字符数组存储多个字符串的比较:两维字符数组存储多个字符串的比较:(1
80、1)节节省省存存储储空空间间( (二二维维数数组组要要按按最最长长的的串串开辟存储空间开辟存储空间) )(2 2)便便于于对对多多个个字字符符串串进进行行处处理理,节节省省处处理理时时间间。(使使用用指指针针数数组组排排序序各各个个串串不不必必移移动动字符数据,只要改变指针指向的地址)字符数据,只要改变指针指向的地址)例例10.6 将若干字符串按字母顺序(由小到大)输出。将若干字符串按字母顺序(由小到大)输出。#include #include void main()void sort(char *name ,int n); void printf(char *name ,int n); ch
81、ar *name =Follow me,BASIC,Great Wall,FORTRAN,Computer design; int ;sort(,); print(,);void sort(char * ,int )char *; int ,; for(; for(; if(strcmp(name,name)0)=; if(!) temp=namei; namei=namek; namek=temp; void print(char * ,int ) ; (;) printf(,); 运行结果为:运行结果为:Computer designFORTRANFollow meGreat Wall10
82、.7.2 10.7.2 指向指针的指针指向指针的指针指指针针的的指指针针:指指向向指指针针变变量量的的指指针针变变量量。指指针针的的指指针针存存放放的是指针变量地址的是指针变量地址.指针变量的指针变量(指针的指针)的定义:指针变量的指针变量(指针的指针)的定义:类型类型*指针变量名;指针变量名; P2 p1 i&p1&i2intint i=2; /* i=2; /* 定义整型变量定义整型变量i */i */intint *p1,*p2; /* *p1,*p2; /* 定义定义p1p1为整型指针,定为整型指针,定义义p2p2为整型指针的指针为整型指针的指针 * */ /p1=&i; /* ip1
83、=&i; /* i的地址的地址=p1=p1,即,指针,即,指针p1p1指向指向变量变量i */i */p2=&p1; /* p2=&p1; /* 指针指针p1p1的地址的地址=p2=p2,即,指针,即,指针p2p2指向指针指向指针p1 */p1 */对对变变量量i i的的访访问问可可以以是是i,*p1,i,*p1,又又因因为为* *p2=p1p2=p1,即即,*p2=*p1p2=*p1,所所以以对对变变量量i i的的访访问问可可以以是是i,*p1,*p2i,*p1,*p2。定义一个指向指针数据的指针变量定义一个指向指针数据的指针变量:*;的前面有两个*号。*运算符的结合性是从右到左,因此*相当
84、于*(*),显然*是指针变量的定义形式。如果没有最前面的*,那就是定义了一个指向字符数据的指针变量。现在它前面又有一个*号,表示指针变量是指向一个字符指针变量的。*就是所指向的另一个指针变量。我我们们知知道道,数数组组的的指指针针是是指指向向数数组组元元素素的的指指针针(整整型型、实实型型、字字符符型型一一维维数数组组的的指指针针分分别别是是指指向向整整型型、实实型型、字字符符型型指指针针,二二维维数数组的指针是指向一维数组的指针);同理:组的指针是指向一维数组的指针);同理:指指针针数数组组的的指指针针,也也是是指指向向其其数数组组元元素素的的指指针针。指指针针数数组组的的数数组组元元素素是
85、是指指针针,所所以以指指向向指指针针数数组组的的指指针针就就是是指指针针的的指指针针。也也就就是是说说,可以使用可以使用“指针的指针指针的指针”指向指针数组指向指针数组。例例10.7 使用指向指针的指针。使用指向指针的指针。 #include void main()char *name=Follow me,BASIC,Great Wall,FORTRAN,Computer design; char *; int ; for(;); printf(,*); 例例10.28 一个指针数组的元素指向整型数据的简单例子一个指针数组的元素指向整型数据的简单例子。#include void main()i
86、nt ,; int *num5=&a0,&a1, &a2,&a3,&a4; int *,; ;for(; printf( ,*); ; 10.7.3 10.7.3 指针数组作指针数组作mainmain函数的形参函数的形参1、main()函数可以带参数。函数可以带参数。main()函数是整个可执行程序的入口(执行起点)。函数是整个可执行程序的入口(执行起点)。main函数函数也与其它函数一样可以带参数,指针数组的一个重要应用是作也与其它函数一样可以带参数,指针数组的一个重要应用是作为为main函数的形参。人们习惯将函数的形参。人们习惯将argc,argv作为作为main()函数的形函数的形参名。
87、参名。带参数带参数main函数的完整的原型是:函数的完整的原型是:类型类型main(intargc,char*argv);其中:其中:(1)argc是传递给是传递给main()函数的函数的参数的个数参数的个数。(包括可执行程序。(包括可执行程序名)名)(2)argv是传递给是传递给main()函数的字符函数的字符指针数组指针数组,该数组各个元素,该数组各个元素是字符指针,分别指向调用是字符指针,分别指向调用main()函数时在操作系统命令行输函数时在操作系统命令行输入的各个字符串。(包括可执行程序名)入的各个字符串。(包括可执行程序名)2、main函数如何获得参数?函数如何获得参数?-从操作系
88、统命令行获得参数。从操作系统命令行获得参数。命令行的一般形式为命令行的一般形式为 命令名命令名参数参数参数参数参数参数例如一个名为file的文件,它包含以下的main函数:void main(int argc,char *argv ) while() argv; printf(,argv); argc; 在DOS命令状态下输入的命令行为则执行以上命令行将会输出以下信息:10.810.8有关指针的数据类型和有关指针的数据类型和指针运算的小结指针运算的小结10.8.110.8.1有关指针的数据类型的小结有关指针的数据类型的小结定定义义含含义义 ;定定义义整型整型变变量量* *;为为指向整型数据的指
89、指向整型数据的指针变针变量量intint a an n; ;定定义义整型数整型数组组,它有个元素,它有个元素 * *;定定义义指指针针数数组组,它由个指向整型数据的指,它由个指向整型数据的指针针元素元素组组成成 (* *););为为指向含个元素的一指向含个元素的一维维数数组组的指的指针变针变量量 ();();为带为带回整型函数回整型函数值值的函数的函数 * *();();为带为带回一个指回一个指针针的函数,的函数,该该指指针针指向整型数据指向整型数据 (* *)();)();为为指向函数的指指向函数的指针针,该该函数返回一个整型函数返回一个整型值值 * *;是一个指是一个指针变针变量,它指向一
90、个指向整型数据的指量,它指向一个指向整型数据的指针变针变量量10.8.2 10.8.2 指针运算小结指针运算小结(1) 指针变量加(减)一个整数指针变量加(减)一个整数例如:、等。(2) 指针变量赋值指针变量赋值将一个变量地址赋给一个指针变量。如:; (将变量的地址赋给)array; (将数组首元素地址赋给)array;(将数组第个元素 的地址赋给)max;(为已定义的函数,将的入口 地址赋给);(和都是指针变量,将的 值赋给) (3) 指针变量可以有空值指针变量可以有空值(dull),即该指针变量不,即该指针变量不指向任何变量指向任何变量。(4) 两个指针变量可以相减两个指针变量可以相减如果
91、两个指针变量都指向同一个数组中的元素,则两个指针变量值之差是两个指针之间的元素个数 。和则无实际意义(5) 两个指针变量比较两个指针变量比较若两个指针指向同一个数组的元素,则可以进行比较。指向前面的元素的指针变量“小于”指向后面元素的指针变量。 10.8.3 void10.8.3 void指针类型指针类型 ANSIC新标准增加了一种“void”指针类型,即可定义一个指针变量,但不指定它是指向哪一种类型数据的。ANSIC标准规定用动态存储分配函数时返回void指针,它可以用来指向一个抽象的类型的数据,在将它的值赋给另一指针变量时要进行强制类型转换使之适合于被赋值的变量的类型。例如:*;*;( *); 同样可以用( *)将的值转换成 *类型。如:( *);也可以将一个函数定义为 *类型,如: *(char ch1,char ch2)表示函数返回的是一个地址,它指向“空类型”,如需要引用此地址,也需要根据情况对之进行类型转换,如对该函数调用得到的地址要进行以下转换:( *)(h,h);