实用C语言序的设计教程第6章2

上传人:m**** 文档编号:578727868 上传时间:2024-08-24 格式:PPT 页数:116 大小:640.53KB
返回 下载 相关 举报
实用C语言序的设计教程第6章2_第1页
第1页 / 共116页
实用C语言序的设计教程第6章2_第2页
第2页 / 共116页
实用C语言序的设计教程第6章2_第3页
第3页 / 共116页
实用C语言序的设计教程第6章2_第4页
第4页 / 共116页
实用C语言序的设计教程第6章2_第5页
第5页 / 共116页
点击查看更多>>
资源描述

《实用C语言序的设计教程第6章2》由会员分享,可在线阅读,更多相关《实用C语言序的设计教程第6章2(116页珍藏版)》请在金锄头文库上搜索。

1、 指针是指针是C语言的语言的个重要特色,是个重要特色,是C语言的精华所在。语言的精华所在。正是丰富的指针运算功能才使得正是丰富的指针运算功能才使得C语言是目前最常用、最流语言是目前最常用、最流行的面向过程的结构化程序设计语言。正确而灵活地运用指行的面向过程的结构化程序设计语言。正确而灵活地运用指针,能有效地表示复杂的数据结构、方便地使用数组和字符针,能有效地表示复杂的数据结构、方便地使用数组和字符串;可以在函数间进行数据传递;可以直接处理内存地址、串;可以在函数间进行数据传递;可以直接处理内存地址、动态分配内存等。熟练、灵活的使用指针,可以使程序简洁、动态分配内存等。熟练、灵活的使用指针,可以

2、使程序简洁、紧凑、高效。紧凑、高效。 本章首先给出指针的概念,然后分别讲述变量的指针、本章首先给出指针的概念,然后分别讲述变量的指针、数组的指针、函数的指针、指针数组、字符指针及指针的指数组的指针、函数的指针、指针数组、字符指针及指针的指针等,并配有一定数量的例题,加深理解。针等,并配有一定数量的例题,加深理解。 第第6章章 指针指针第第6章章 指针指针6.1 内存数据的指针与指针变量内存数据的指针与指针变量6.2 指针变量的定以及指针运算指针变量的定以及指针运算 6.3 数组元素的指针与数组的指针数组元素的指针与数组的指针 6.4 函数的指针和返回指针的函数函数的指针和返回指针的函数 6.5

3、 字符指针字符指针6.6 指针数组与指向指针的指针指针数组与指向指针的指针6.7 本章小结本章小结 6.1 内存数据的指针与指针变量内存数据的指针与指针变量 指针既是指针既是C语言的重点,也是语言的重点,也是C语言的难点之一。简语言的难点之一。简单的地说,指针就是内存单元的地址。为深刻理解指针单的地说,指针就是内存单元的地址。为深刻理解指针的概念,必须弄清楚内存的概念以及数据在内存中是如的概念,必须弄清楚内存的概念以及数据在内存中是如何存储的,又是如何读取的。何存储的,又是如何读取的。 我们都知道,在计算机的硬件构成中,主机是由运我们都知道,在计算机的硬件构成中,主机是由运算器、控制器和存储器

4、组成,前两者合在一起称为中央算器、控制器和存储器组成,前两者合在一起称为中央处理器,简称处理器,简称CPU,而存储器又分为内部存储器和外部,而存储器又分为内部存储器和外部存储器,简称内存和外存,所有数据只有存放在内存中存储器,简称内存和外存,所有数据只有存放在内存中计算机才能进行处理和运算。内存计量的基本单位是字节,计算机才能进行处理和运算。内存计量的基本单位是字节,它是进行分配和读取的最小单位,每个字节由它是进行分配和读取的最小单位,每个字节由8个二进制个二进制位(位(bit)组成,一个字节就是一个内存单元。整个内存)组成,一个字节就是一个内存单元。整个内存空间是一维的,每个字节都有一个唯一

5、的序号,称为内存空间是一维的,每个字节都有一个唯一的序号,称为内存单元的地址,比如对一个单元的地址,比如对一个1Mb的内存,其内存单元的地址的内存,其内存单元的地址分别为分别为0,1,2,3, ,。,。 任何计算机程序只有存贮在内存中才能被执行。操作任何计算机程序只有存贮在内存中才能被执行。操作系统要占用一些计算机内存空间,每个应用程序也要占用系统要占用一些计算机内存空间,每个应用程序也要占用计算机内存空间。按照面向过程的结构化程序设计方法,计算机内存空间。按照面向过程的结构化程序设计方法,程序代码和程序要处理的数据是分开存贮的。所以,一个程序代码和程序要处理的数据是分开存贮的。所以,一个程序

6、在内存中要占两部分存储空间:数据部分和指令代码程序在内存中要占两部分存储空间:数据部分和指令代码部分。部分。 此此处处只只考考察察数数据据段段在在内内存存中中的的存存贮贮情情况况。当当C程程序序中中定定义义一一个个变变量量时时,编编译译系系统统划划分分一一定定数数目目的的存存贮贮单单元元来来存存贮贮那那个个变变量量,存存贮贮单单元元的的数数目目由由变变量量的的类类型型确确定定,例例如如,一一般般微微机机使使用用的的C语语言言系系统统为为整整型型变变量量分分配配2个个字字节节,对对实实型型变变量量分分配配4个个字字节节,对对字字符符型型变变量量分分配配1个个字字节节等等,若若变变量量分分配配的的

7、不不是是1个个字字节节,此此时时以以变变量量分分配配的的第第一一个个字字节节的的地地址址作作为为该该变变量量存存储储地地址址,这这就就是是内内存存数数据据的的指指针针,编编译译系系统统把把这这几几个个存存贮贮单单元元与与变变量量名名联联系系起起来来。如如有有一一整整型型变变量量,变变量量名名是是n,值值是是999,占占用用的的存存贮贮单单元元是是3000和和3001两两个个字字节节,则变量则变量n的内存地址是的内存地址是3000。 一一定定要要清清楚楚变变量量的的地地址址与与变变量量的的值值不不是是一一回回事事,变变量量的的地地址址是是由由编编译译系系统统按按一一定定规规则则进进行行分分配配的

8、的,一一经经分分配配就就固固定定不不变变,变变量量的的值值在在程程序序运运行行过过程程中中是是可可以以改改变变的的,用用户户需需要要关关心心的的是是变变量量的的当当前前值值,而而不不必必关关心心变变量量的的地地址址,即变量存储单元。即变量存储单元。 当程序引用这个变量时,可通过变量名自动地访问相当程序引用这个变量时,可通过变量名自动地访问相应的存贮单元,当然程序也可以通过该变量的地址来访问应的存贮单元,当然程序也可以通过该变量的地址来访问这些存贮器单元。按变量地址存取变量值的访问方式称为这些存贮器单元。按变量地址存取变量值的访问方式称为“直接访问直接访问”方式。如对上面提到的变量方式。如对上面

9、提到的变量n,为了得到其,为了得到其值,可直接读出值,可直接读出3000和和3001两个字节的值即可,赋值语两个字节的值即可,赋值语句句n=456;将变量;将变量n的值改为的值改为456,系统只需把,系统只需把456写到写到3000和和3001两个字节中即可。两个字节中即可。 在在C语言中,可以定义一种特殊的变量,它是专门用语言中,可以定义一种特殊的变量,它是专门用来存放变量的存储单元的地址,称为指针变量。这样对来存放变量的存储单元的地址,称为指针变量。这样对变量的访问可以采用另一种称之为变量的访问可以采用另一种称之为“间接访问间接访问”的方式,的方式,例如,我们可先定义一个存放整型变量的地址

10、的指针变例如,我们可先定义一个存放整型变量的地址的指针变量量n_prt,不妨设变量,不妨设变量n_prt被分配在被分配在3086、3087字节,字节,用语句用语句n_prt=&n;将上面的变量;将上面的变量n的地址(的地址(3000)存放)存放在在n_prt中,这样就可以通过指针变量中,这样就可以通过指针变量n_prt来访问变量来访问变量n,即先通过变量,即先通过变量n_prt的地址的地址3086得到变量得到变量n_prt的值的值为为3000,它就是地址,再访问,它就是地址,再访问3000单元的内容,如图单元的内容,如图6-1所示。所示。物理内存物理内存 3000456变量变量n3002308

11、63000变量变量n_prt 3088图 6-1 如果要将变量如果要将变量n的值改为的值改为1234,则用赋值语句,则用赋值语句n=1234;和;和*n_prt=1234;的效果是一致的,前者是;的效果是一致的,前者是直接访问,而后者是间接访问。其中符号直接访问,而后者是间接访问。其中符号“&”和和“*”是两个重要的指针运算符是两个重要的指针运算符“取地址取地址”和和“取值取值” 运算运算符。符。 需要说明的是,指针类型是对所有类型的指针的总需要说明的是,指针类型是对所有类型的指针的总称,指针的类型是指针所指对象的数据类型。例如,称,指针的类型是指针所指对象的数据类型。例如,n_prt是指向整

12、型变量的指针,简称整型指针。除各种是指向整型变量的指针,简称整型指针。除各种基本类型的指针外,允许定义指向数组的指针、指向函基本类型的指针外,允许定义指向数组的指针、指向函数的指针、指向结构体和共用体的指针以及指向各类指数的指针、指向结构体和共用体的指针以及指向各类指针的指针。在针的指针。在C语言中只有指针被允许用来存放地址的语言中只有指针被允许用来存放地址的值,其它类型的变量只能存放该类型的数据。值,其它类型的变量只能存放该类型的数据。6.2 6.2 指针变量的定义及指针运算指针变量的定义及指针运算6.2.1 指针变量的定义指针变量的定义 6.2.2 指针变量的运算指针变量的运算6.2.3

13、指针变量作为函数的参数指针变量作为函数的参数 变量的指针就是变量的地址,专门用来存放变量地址变量的指针就是变量的地址,专门用来存放变量地址的变量称为指针变量。的变量称为指针变量。C语言规定所有变量在使用前必须语言规定所有变量在使用前必须定义,指针变量也不例外,定义指针变量的一般形式是:定义,指针变量也不例外,定义指针变量的一般形式是: 类型标识符类型标识符 * *指针变量名;指针变量名; 这里,类型标识符说明该指针变量用来存放哪一种类这里,类型标识符说明该指针变量用来存放哪一种类型的变量的地址,可以是基本类型,也可以是构造类型,型的变量的地址,可以是基本类型,也可以是构造类型,如结构体类型、指

14、针类型等。指针变量名前的如结构体类型、指针类型等。指针变量名前的“*”不可不可少,它表明该变量是指针变量。例如少,它表明该变量是指针变量。例如 6.2.1 指针变量的定义 int i ,j, k; float x, y; int *p1, *p2,*p3; float *p4,*p5; 以上说明语句,定义了以上说明语句,定义了3个指向整型数据的指针变量个指向整型数据的指针变量和和2个指向实型数据的指针变量(此时,它们并没有指向个指向实型数据的指针变量(此时,它们并没有指向某一具体变量)。既然指针变量存放的是变量的地址,它某一具体变量)。既然指针变量存放的是变量的地址,它的值就不允许用户随意指定

15、,这样就会造成混乱,指针变的值就不允许用户随意指定,这样就会造成混乱,指针变量的值可以通过取地址运算和地址赋值运算来取得。如量的值可以通过取地址运算和地址赋值运算来取得。如 p1=&i; p2=&j; p3=p2; p4=&x; p5=p4;此时,我们称指针变量此时,我们称指针变量p1指向变量指向变量i ,指针变量,指针变量p2和和p3同同时指向变量时指向变量j,指针变量,指针变量p4和和p5同时指向变量同时指向变量x。但是语句。但是语句 p2=&y; p5=p1; p3=2800;都是错误的。因为一个指针变量只能指向同一个类型的变量,都是错误的。因为一个指针变量只能指向同一个类型的变量,只能

16、把指针(地址)赋给指针变量。只能把指针(地址)赋给指针变量。同普通变量一样,指针变量的赋初值也可在定义时进行。如同普通变量一样,指针变量的赋初值也可在定义时进行。如 int num =5, *prt ; prt=#与与 int num =5, *prt=#是等效的。是等效的。 1&和和*运算运算(1)& 取地址运算符。取地址运算符。(2)* 取值运算符。取值运算符。&和和*运算是同级运算,结合性是运算是同级运算,结合性是“从右至左从右至左”,运算级别,运算级别低于低于( )、 、+、- -、.等运算,高于算术、位移、等运算,高于算术、位移、关系、赋值等运算。关系、赋值等运算。2

17、+和和- -运算运算指针变量的指针变量的+和和- -运算与指针变量的类型有关,确切地运算与指针变量的类型有关,确切地说,是与指针变量的类型所占用的存储字节的个数有关。说,是与指针变量的类型所占用的存储字节的个数有关。6.2.2 6.2.2 指针变量的运算指针变量的运算假如指向变量的指针变量假如指向变量的指针变量pointer的值是的值是4000,若,若pointer指向指向的是整型变量的是整型变量a,则分别执行,则分别执行pointer+和和pointer-后,后,pointer的值分别是的值分别是4002和和3998;若;若pointer指向的是实型变指向的是实型变量,则分别执行量,则分别执

18、行pointer+和和pointer-后,后,pointer的值分别的值分别是是4004和和3996。但是,需要注意,变化后指针变量所指单元可。但是,需要注意,变化后指针变量所指单元可能没有值,也可能不是所期望的值,这一点应引起重视。能没有值,也可能不是所期望的值,这一点应引起重视。3指针的比较运算指针的比较运算同类型的指针变量可以作比较运算、差运算,不能做加运算。同类型的指针变量可以作比较运算、差运算,不能做加运算。 以下给出一些指针运算的结论:以下给出一些指针运算的结论:*&a与与a等价等价&*pointer与与pointer等价等价(*pointer)+与与a+等价等价*(pointer

19、+)即即*pointer+都能得到都能得到a的值,但的值,但pointer已不再指向变量已不再指向变量a*pointer+1与与a+1等价等价例例6-1 指针运算的例子。指针运算的例子。main() int a=10,b=30,*p1=&a,*p2=&b; printf(%d %d %d %d %o %o %o %on,a,b,*p1,*p2,p1,p2,&p1,&p2); a+;(*p2)+; printf(%d %d %d %d %o %o %o %on,a,b,*p1,*p2,p1,p2,&p1,&p2); *p1+;*p2-; printf(%d %d %d %d %o %o %o %

20、on,a,b,*p1,*p2,p1,p2,&p1,&p2); a=123;*p2=99;b=88; printf(%d %d %d %d %o %o %o %on,a,b,*p1,*p2,p1,p2,&p1,&p2); p1+;p2+; printf(%d %d %d %d %o %o %o %on,a,b,*p1,*p2,p1,p2,&p1,&p2); printf(%d %dn,p1-p2,p2-p1); 程序的执行结果是:程序的执行结果是: 10 30 10 30 177712 177714 177716 177720 11 31 11 31 177712 177714 177716 1

21、77720 11 31 31 11 177714 177712 177716 177720 99 88 88 99 177714 177712 177716 177720 99 88 -50 88 177716 177714 177716 177720 1 -1 执行结果中前执行结果中前4个值说明个值说明a与与*p1等价,等价,b与与*p2等价,后等价,后4个值分别用八进制输出的变量个值分别用八进制输出的变量a,b, p1,p2的地址,但需说明的的地址,但需说明的是在不同的环境下这些值未必就是上述值。第是在不同的环境下这些值未必就是上述值。第2行说明执行行说明执行(*p2)+与与b+是等价的。

22、第是等价的。第3行说明执行行说明执行*p1+和和*p2-后,后,a,b的值不变,的值不变,p1+的结果正好是原的结果正好是原p2的值(的值(177714),),p2-的结果正好是原的结果正好是原p1的值(的值(177712),即),即p1指向指向b,p2指指向向a。第。第4行的说明执行行的说明执行*p2=99等价于等价于a=99,因为此时,因为此时p2是是指向指向a的,的,b=88存储在存储在177714单元。第单元。第5行的说明执行行的说明执行p1+和和p2+后,后,p1和和p2的值分别为的值分别为177716和和177714,此时此时p2又指向又指向b, p1指向的指向的177716单元的

23、值无意义。第单元的值无意义。第6行输出的不是行输出的不是2和和-2,而是,而是1和和-1,说明说明p1指向指向p2的下一个存储单元,此时意义不大,后面将的下一个存储单元,此时意义不大,后面将会看到,当两个指针指向同一数组的元素时,指针的差才会看到,当两个指针指向同一数组的元素时,指针的差才有意义。我们还可以看到,变量有意义。我们还可以看到,变量a、b、p1、p2的地址是的地址是始终不变的。始终不变的。 上一章已经提到,指针变量也可作为函数的参数,此时函上一章已经提到,指针变量也可作为函数的参数,此时函数的实参与形参之间是数的实参与形参之间是地址传递地址传递。 例例6-2 输入两个整数输入两个整

24、数a,b, 按先大后小的顺序输出按先大后小的顺序输出a和和b。 程序程序1:不用子函数,在主函数中交换指针变量的的值。:不用子函数,在主函数中交换指针变量的的值。 6.2.3 6.2.3 指针变量作为函数的参数指针变量作为函数的参数main() int a,b,*p,*p1,*p2; printf(input 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(max=%d min=%dn,*p1,*p2); 程序执行结果如下:程序执行结果如下: inpu

25、t a,b=10 50 a=10 b=50 max=50 min=10当当ab时,指针变量时,指针变量p1和和p2交换后,交换后,p1指向指向b(较(较大的值),大的值),p2指向指向a(较小(较小的值)。的值)。&ap110a&ap110a&bp250b&bp250b&ap交换前交换前交换后交换后交换前后的情况见图交换前后的情况见图6-2。图图6-2程序程序2:在子函数中交换指针变量所指的值。:在子函数中交换指针变量所指的值。 void swap(int *p1, int *p2) int temp; temp=*p1; *p1=*p2; *p2=temp; main() int a,b,*

26、pa,*pb; printf(input a,b=); scanf(%d %d,&a,&b); printf( a=%d b=%dn,a,b); pa=&a;pb=&b; if(ab) swap(pa,pb); printf( a=%d b=%dn,a,b); printf(*pa=%d *pb=%dn,*pa,*pb); 程序执行结果如下:程序执行结果如下: input a,b= 10 50 a=10 b=50 a=50 b=10 *pa=50 *pb=10当当ab时,函数时,函数swap把指针变量把指针变量pa和和pb所指的值所指的值10和和50做了交换,做了交换,pa仍指向仍指向a=50

27、, pb仍指向仍指向b=10。交换前后。交换前后的情况见图的情况见图6-3。50a10b50a10b&ap1&apa&bpb&bp2&apa&bpb10a&ap1&apa50b&bpb&bp210a&apa50b&bpb10temp调用调用swap函数前函数前swap函数函数执行前执行前swap函数函数返回前返回前swap函数函数返回后返回后图图 6-3程序程序3:在子函数中交换指针变量所指的值。:在子函数中交换指针变量所指的值。 void swap(int *p1, int *p2) int *p; p=p1; p1=p2; p2=p; main() int a,b,*pa,*pb; pri

28、ntf(input a,b=); scanf(%d %d,&a,&b); printf( a=%d b=%dn,a,b); pa=&a; pb=&b; if(ab) swap(pa,pb);printf( a=%d b=%dn,a,b);printf(*pa=%d *pb=%dn,*pa,*pb); 程序执行结果如下:程序执行结果如下: input a,b= 10 50 a=10 b=5 a=10 b=50 *pa=10 *pb=50 程序执行结果没有完成预期目的。因为当程序执行结果没有完成预期目的。因为当ab时,函数时,函数swap把指针变量把指针变量pa和和pb的值做了交换,在的值做了交换

29、,在swap函数返回函数返回前,形参前,形参p1指向指向b=50,p2指向指向a=10,但在,但在swap函数返回函数返回时,时,p1和和p2的值并不能传递给实参的值并不能传递给实参pa和和pb。因为。因为C语言中实语言中实参变量和形参变量之间的数据传递是单向的参变量和形参变量之间的数据传递是单向的“值传递值传递”方式。方式。指针变量作函数参数也要遵循这一规则。调用函数不可能改指针变量作函数参数也要遵循这一规则。调用函数不可能改变实参指针变量的值,但可以改变实参指针变量所指变量的变实参指针变量的值,但可以改变实参指针变量所指变量的值。交换前后的情况见图值。交换前后的情况见图6-4。10a50b

30、10a50b&apa&bpb&apa&bpb10a&apa50b&bpb10a&apa50b&bpb&ap调用调用swap函数前函数前swap函数函数执行前执行前swap函数函数返回前返回前swap函数函数返回后返回后图图 6-4例例6-3 输入输入a,b,c 3个整数,按大小顺序输出。个整数,按大小顺序输出。void swap(int *pt1, int *pt2) int temp; temp=*pt1; *pt1=*pt2; *pt2=temp;void exchang(int *q1,int *q2,int *q3) if(*q1*q2)swap(q1,q2); if(*q1*q3)s

31、wap(q1,q3); if(*q2*q3)swap(q2,q3);main() int a,b,c,*p1,*p2,* p3; printf(input a,b,c=); scanf(%d,%d,%d,&a,&b,&c) p1=&a;p2=&b;p3=&c; exchangc(p1,p2,p3); printf(%d,%d,%dn,a,b,c); 程序执行结果如下:程序执行结果如下:input a,b,c= 1,2,33,2,16.3 数组元素的指针数组元素的指针 与数组的指针与数组的指针 数数组组是是由由若若干干同同类类型型的的数数据据元元素素组组成成的的构构造造类类型型,在在内内存存中中

32、占占用用一一段段连连续续的的存存储储单单元元。指指针针变变量量既既然然可可以以指指向向变变量量,当当然然也也可可以以指指向向数数组组元元素素,所所谓谓数数组组元元素素的的指指针针就就是是数数组组元元素素的的首首地地址址,数数组组的的指指针针就就是是数数组组的的首首地地址址,它它也也是是数数组组的的第第1元元素素的的地地址址。引引入入指指针针后后,对对数数组组元元素素的的引引用用可可以以用用下下标标法法,也也可可以以用用指指针针法法,即即通通过过指指向向数数组组元元素素的的指指针针找找到到所所需需的的元元素素。使使用用指指针针法法访访问问数组元素能使目标程序占内存少且运行速度快。数组元素能使目标

33、程序占内存少且运行速度快。6.3 数组元素的指数组元素的指 针与数组的指针针与数组的指针 6.3.2 数组的指针数组的指针6.3.3 多维数组的指针多维数组的指针6.3.4 指向由指向由m个元素组成的个元素组成的 一维数组的指针变量一维数组的指针变量6.3.1 数组元素的指针数组元素的指针1. 1. 指向数组元素的指针变量指向数组元素的指针变量 数组中的每一元素要占用一段存储单元,其第数组中的每一元素要占用一段存储单元,其第1个字节的地个字节的地址就是该数组元素的地址。如果定义一个指向数组元素的指址就是该数组元素的地址。如果定义一个指向数组元素的指针变量,就可以用指针变量访问数组元素。定义形式

34、与定义针变量,就可以用指针变量访问数组元素。定义形式与定义指向变量的指针变量相同。如指向变量的指针变量相同。如 int array20,num; int *p; 此时此时p是一个只能指向整型数据的指针变量。可以令是一个只能指向整型数据的指针变量。可以令 p=&array5;6.3.1 6.3.1 数组元素的指针数组元素的指针则则p指向数组元素指向数组元素array5。也可以令。也可以令 p=#则则p指向整型变量指向整型变量num。同样地,可以在定义指向数组元素的。同样地,可以在定义指向数组元素的指针变量同时,对其赋初值。如指针变量同时,对其赋初值。如 int array20,*prt=

35、&array0;和和 int array20,*prt=array;是等效的,因为是等效的,因为array既是数组的地址,也是第既是数组的地址,也是第1个数组元素个数组元素 array0的地址。的地址。2. 2. 用指针变量访问数组元素用指针变量访问数组元素 用指向数组元素的指针变量访问数组元素可以提高程序用指向数组元素的指针变量访问数组元素可以提高程序的效率。设有语句的效率。设有语句 int a 20,*p=&a 0;则则 (1) p+i和和a+i都表示都表示ai的地址,即它们都指向数组的地址,即它们都指向数组元素元素ai。 (2) *(p+i)和和*(a+i) 都是都是p+i或或a+i所指

36、向的数组元素所指向的数组元素ai。 事实上,编译程序对数组元素事实上,编译程序对数组元素ai就是处理成就是处理成*(a+i),即,即按数组首元素的地址加上相对位移量得到要找的元素的地址,按数组首元素的地址加上相对位移量得到要找的元素的地址,然后找出该单元中的内容。这也是然后找出该单元中的内容。这也是C语言把数组的最小语言把数组的最小下标规定为下标规定为0的原因。在运算符表中,下标运算符的原因。在运算符表中,下标运算符 实际上实际上是变址运算符,即将是变址运算符,即将ai按按a+i计算地址,然后找出此地址单计算地址,然后找出此地址单元中的值。元中的值。 (3) 指向数组的指针变量也可以带下标,如

37、指向数组的指针变量也可以带下标,如*(p+i)也可写也可写成成 pi,二者是等价的。,二者是等价的。 (4) 虽然虽然p和和a都是指针,但都是指针,但p的值可变,而的值可变,而a的值不可变,的值不可变,即即p可指向任一数组元素,而可指向任一数组元素,而a始终指向数组元素始终指向数组元素a0。如。如p+是合法的,而是合法的,而a+是非法的。是非法的。 根据以上可知,引用一个数组元素,可以用下标法(如根据以上可知,引用一个数组元素,可以用下标法(如ai形式)和指针法(如形式)和指针法(如*(a+i)或或*(p+i)形式)。形式)。例例6-4引用一个数组元素的例子。引用一个数组元素的例子。main(

38、) int a10,i, *p; for(i=0;i10;i+) scanf(%d,&ai); printf(n); for(i=0;i10;i+) printf(%d ,ai); printf(n);for(i=0;il0,i+) print(%d ,*(a+i);printf(n);for(p=a;p(a+10);) printf(%d , *p+); 程序执行时会发现,用三种方式程序执行时会发现,用三种方式ai、*(a+i)、*p+输出数组元素,结果相同。输出数组元素,结果相同。 数组的指针就是数组首元素的地址。用数组名作为函数的数组的指针就是数组首元素的地址。用数组名作为函数的参数,实

39、参数组名代表该数组首元素的地址,而形参是用来接参数,实参数组名代表该数组首元素的地址,而形参是用来接收从实参传递过来的数组首元素的地址。因此,形参应该是一收从实参传递过来的数组首元素的地址。因此,形参应该是一个指针类型的量,可以是指针变量也可以是数组名。实际上,个指针类型的量,可以是指针变量也可以是数组名。实际上,C编译系统就是将形参数组名作为指针变量来处理的。编译系统就是将形参数组名作为指针变量来处理的。 实参数组和形参数组各元素间并不存在实参数组和形参数组各元素间并不存在“值传递值传递”,在函,在函数调用时,形参数组并不开辟新的存储单元,而是以实参数组数调用时,形参数组并不开辟新的存储单元

40、,而是以实参数组的首地址作为形参数组的首地址,使形参数组和实参数组共享的首地址作为形参数组的首地址,使形参数组和实参数组共享一段存储空间。正是共享的缘故,才使得函数中对形参数组元一段存储空间。正是共享的缘故,才使得函数中对形参数组元素的改变就是对实参数组元素的改变,函数调用结束后,改变素的改变就是对实参数组元素的改变,函数调用结束后,改变的结果得以保留,可以得到多个改变后的值。的结果得以保留,可以得到多个改变后的值。6.3.2 6.3.2 数组的指针数组的指针例例6-5 将数组将数组a中中n个整数按相反顺序存放。个整数按相反顺序存放。 题目分析:在例题目分析:在例5-6和例和例5-14中已熟悉

41、了数组元素反顺中已熟悉了数组元素反顺序存放的算法,这里通过本题加深对数组的指针、数组元序存放的算法,这里通过本题加深对数组的指针、数组元素的指针和数组名作为函数参数的参数传递的了解。素的指针和数组名作为函数参数的参数传递的了解。程序如下:程序如下: void invert (int x ,int n) *形参形参x是数组名是数组名* int temp,i,j,m=n/2; for(i=0;im;i+) j=n-1-j; temp=xi; xi=xj; xj=temp; return;main() int i; static int al01,2,3,4,5,6,7,8,9,10; printf

42、(The original array:n); for(i=0;i10;i+) printf(%d,,ai); printf(n); invert(a,10);printf(The array has been inverted:n);for(i=0;i10;i+) printf(d,, ai);printf(n);运行情况如下:运行情况如下:The original array:1,2,3,4,5,6,7,8,9,10,The array has been inverted:10,9,8,7,6,5,4,3,2,1, 对对invert函数作一些改动,形参函数作一些改动,形参x改成指针变量。改

43、动后的改成指针变量。改动后的invert函数如下:函数如下: void invert(int *x, int n) /*形参形参x为指针变量为指针变量*/ int temp,*p,*i,*j,m=n/2; i=x; j=x+n1; p=x+m; for(;ip; i+,j-) temp*i; *i;=*j; *j=temp; return; 主函数对主函数对invert函数调用时的实参也可使用指针变量,改函数调用时的实参也可使用指针变量,改动后的动后的main函数如下:函数如下: main() int i,arrl0,*p=arr; printf(The original array:n);

44、for(i=0;i10;i+,p+) printf(%d,,p); printf(“n”); p=arr; invert(p,10);*指针重置为数组指针重置为数组arr的首地址的首地址* printf(the array has been inveried:n); for(p=arr;parr+10;p+) printf(%d,*p); printf(“n”); 至此我们可以看到,数组名作为函数参数的地址传递至此我们可以看到,数组名作为函数参数的地址传递有以下四种方法:有以下四种方法:(1)实参用数组名,形参用数组名;)实参用数组名,形参用数组名;(2)实参用数组名,形参用指针变量;)实参用

45、数组名,形参用指针变量;(3)实参用指针变量,形参用数组名;)实参用指针变量,形参用数组名;(4)实参用指针变量,形参用指针变量。)实参用指针变量,形参用指针变量。 数组是数组是C语言的一个构造类型,其元素可以是语言的一个构造类型,其元素可以是C语言的任语言的任何类型,包括数组本身。也就是说,数组可以作为另一个数组何类型,包括数组本身。也就是说,数组可以作为另一个数组的数组元素。这样,多维数组的问题就迎忍而解了,在的数组元素。这样,多维数组的问题就迎忍而解了,在C语言语言中,数组在实现方法上只有一维的概念,多维数组被看成以下中,数组在实现方法上只有一维的概念,多维数组被看成以下一级数组为元素的

46、数组。一级数组为元素的数组。 设有一个二维数组的定义为:设有一个二维数组的定义为: static int a24=1,3,5,7,2,4,6,8; 表面上看,表面上看,a是一个二维数组名,我们也可以将它看成是一是一个二维数组名,我们也可以将它看成是一个一维数组名。它包含两个数组元素,分别为个一维数组名。它包含两个数组元素,分别为a0和和a1。6.3.3 6.3.3 多维数组的指针多维数组的指针每个数组元素又包含四个元素,例如,数组每个数组元素又包含四个元素,例如,数组a0包含四个包含四个元素,分别为:元素,分别为:a00、a01、a02和和a03,数组,数组a1包含四个元素,分别为:包含四个元

47、素,分别为:a10、a11、a12和和a13。a0和和a1虽然没有单独地、显式虽然没有单独地、显式地定义,它们却可以被认为是数组名,是数组在内存中的地定义,它们却可以被认为是数组名,是数组在内存中的首地址,这一点与数组名首地址,这一点与数组名a一样,但与一样,但与a的类型不同,也的类型不同,也就是数组元素的类型不同。就是数组元素的类型不同。a0和和a1数组的元素类型数组的元素类型为整型数,而为整型数,而a数组的元素类型为整型数组。数组的元素类型为整型数组。 假设数组假设数组a在内存中的分配情况如表在内存中的分配情况如表6-1所示。所示。 数组数组元素元素a00a01a02a03a10a11a1

48、2a13地址地址20002002200420062008201020122014元素元素值值13572468表表 6-1可以看到对于数组可以看到对于数组a来说,它所占用的内存空间是连续的。如果来说,它所占用的内存空间是连续的。如果我们将我们将a视为一维数组的话,那么它的两个数组元素视为一维数组的话,那么它的两个数组元素a0和和a1所占用的内存空间也是连续的,此时每个数组元素占用所占用的内存空间也是连续的,此时每个数组元素占用8个内存单元。当然如果将个内存单元。当然如果将a视为二维数组的话,它的视为二维数组的话,它的8个数组元个数组元素所占用的内存空间也是连续的,此时每个数组元素占用素所占用的内

49、存空间也是连续的,此时每个数组元素占用2个个内存单元。另外,二维数组是按行优先次序存储的。内存单元。另外,二维数组是按行优先次序存储的。 C语言程序中数组及其数组元素的表示形式有很多。为了语言程序中数组及其数组元素的表示形式有很多。为了更清楚地说明,我们可以上面定义把二维数组更清楚地说明,我们可以上面定义把二维数组a看成是一个两看成是一个两行四列的形式。这样对于二维数组可以认为行四列的形式。这样对于二维数组可以认为a为首行地址为首行地址(即第即第0行地址行地址),而,而a+1为第为第1行地址;行地址;a0为首行首列地址,而为首行首列地址,而a0+1为第为第0行第行第1列地址。列地址。 a13,

50、*(a1+3),*(*(a+1)+3)表示同一个元素,值为表示同一个元素,值为8。 具体说明见表具体说明见表6-2。表现形式表现形式类型类型含义含义值值a, &a0行地址行地址 第第0行的地址行的地址2000*a, a0列地址列地址 第第0行第行第0列的地址列的地址 2000a+1, &a1行地址行地址 第第1行的地址行的地址2008*(a+1), a1列地址列地址 第第1行第行第0列的地址列的地址 2008*(a+1)+3,a1+3,&a13列地址列地址 第第1行第行第3列的地址列的地址 2014*(*(a+1)+3),*(a1+3),a13整型整型第第1行第行第3列的元素列的元素 8表表

51、6-2 要正确区分要正确区分行地址行地址和和列地址列地址,如,如a,&a0,a+1,&a1都是行地址,而都是行地址,而a+1,&a1, *(a+1),a1,*(a+1)+2等等都是列地址,行地址加都是列地址,行地址加1指向下一行的首地址,列地址加指向下一行的首地址,列地址加1指指向下一个元素的地址。向下一个元素的地址。例例6-6 多维数组的指针。多维数组的指针。main() static int a34=1,3,5,7,2,4,6,8,10,20,30,40; int *p;for (p=a0;p*a+12;p+) if (p-a0)%4=0)printf(“n”); printf(%4d,*

52、p); 程序执行结果如下:程序执行结果如下: 1 3 5 7 2 4 6 810 20 30 40 既然用指针变量来存放列地址,那么同样可以用指针变既然用指针变量来存放列地址,那么同样可以用指针变量来存放行地址,定义存放行地址的指针变量的形式为:量来存放行地址,定义存放行地址的指针变量的形式为: 类型名类型名 (*(*指针名指针名)数组长度数组长度 ; 约束行指针类型的条件有两个,一是它所指向数组的类型;约束行指针类型的条件有两个,一是它所指向数组的类型;一是每行的列数。如语句一是每行的列数。如语句 int (*p)4; 说明说明p是一个指针变量,它指向包含是一个指针变量,它指向包含4个整型元

53、素的一维数个整型元素的一维数组。注意组。注意*p两侧的括号不可缺少,如果写成两侧的括号不可缺少,如果写成*p4,由于,由于6.3.4 6.3.4 指向由指向由m m个元素组成的个元素组成的 一维数组的指针变量一维数组的指针变量方括号方括号 运算级别高,则运算级别高,则p先与先与4结合,是数组,然后再与结合,是数组,然后再与前面的前面的*结合,结合,*p4是指针数组是指针数组(见见6.6节节)。 *p有有4个元素个元素(*p)0、(*p)1、(*p)2和和(*p)3,每,每个元素为整型,也就是个元素为整型,也就是p所指的对象是有所指的对象是有4个整型元素的数组,个整型元素的数组,即即p是行指针,

54、此时是行指针,此时p只能指向一个包含只能指向一个包含4个元素的一维数组,个元素的一维数组,p的值就是该一维数组的首地址,的值就是该一维数组的首地址,p不能指向一维数组中的第不能指向一维数组中的第j个元素。个元素。如果用如果用p指向一个二维数组的行地址,如令指向一个二维数组的行地址,如令 p=a;则则 p+i是数组第是数组第i行的首地址,行的首地址, *(p+i) 是数组第是数组第i行第行第0列元素的地址,列元素的地址, *(p+i)+j是数组第是数组第i行第行第j列元素的地址,列元素的地址, (*(p+i)+j) 是数组第是数组第i行第行第j列元素的值,即列元素的值,即aij。例例6-7 多维

55、数组的行指针。多维数组的行指针。 main() static int a34=1,3,5,7,2,4,6,8,10,20,30,40; int i,j,(*p)4; p=a; for(i=0;i3;i+) for(j=0;j4;j+) printf(“%4d”,*(*(p+i)+j); printf(n); 程序执行结果与上例相同。程序执行结果与上例相同。 注意程序中的表达式注意程序中的表达式*(*(p+i)+j)还可以表示成还可以表示成pij或或(*(p+i)j。 多维数组的地址也可作为函数参数传递,在用指针变多维数组的地址也可作为函数参数传递,在用指针变量作形参以接受实参数组名传递来的地址

56、时,有两种方法:量作形参以接受实参数组名传递来的地址时,有两种方法:用指向变量的指针变量;用指向变量的指针变量;用指向一维数组的指针变量。用指向一维数组的指针变量。 例例6-8 有一个班,有一个班,3个学生,各学个学生,各学4门课,计算总平均门课,计算总平均分数,输出第分数,输出第n个学生的成绩个学生的成绩,找出有不及格课程的学生并找出有不及格课程的学生并输出他们的输出他们的4门课成绩。门课成绩。 题目分析:可用一个题目分析:可用一个3行行4列的二维数组存储题目给出的列的二维数组存储题目给出的数据,设计数据,设计average函数用来求总平均成绩,函数用来求总平均成绩,outdata函数函数用

57、来找出并输出第个用来找出并输出第个i学生的成绩学生的成绩, search查找有不及格课查找有不及格课程的学生并输出成绩。在程的学生并输出成绩。在average函数中使用指向变量的指函数中使用指向变量的指针变量,在针变量,在outdata函数和函数和search函数中使用指向一维数函数中使用指向一维数组的指针变量。组的指针变量。程序如下:程序如下:float average(float *p,int n) float *p_end,sum=0,aver; p_end=p+n-1; for(;p=p_end;p+) sum=sum+(*p); aver=sumn; return aver;void

58、 outdata (float (*p)4,int i) int j; printf(the score of NO.%d are:n,k) for(i=0;i4;i+) printf(%5.2f,*(*(p+i)+j); void search(float (*p)4,int n)int i,j,flag; for(i=0;in;i+) flag=0; for(j=0;j4;j+) if (*(*(p+i)+j60) flag=1; if (flag= =1) printf(No. %d is faile,his score are:n,i+1); for(j=0;jy?x:y); int

59、add(int x,int y) return (x+y); int sub(int x,int y) return (x-y); void operate(int x,int y,int (*fun)() ) printf(%dn,(*fun)(x,y); main() int a,b; scanf(%d%d,&a,&b); printf(Max=); operate(a,b,max); printf(Add=); operate(a,b,add); printf(Sub=); operate(a,b,sub);程序执行情况如下:程序执行情况如下:10 20Max=20Add=30Sub=-

60、10 C语言中函数可以返回除数组、共用体变量和函数语言中函数可以返回除数组、共用体变量和函数以外的任何类型数据和指向任何类型的指针。以外的任何类型数据和指向任何类型的指针。返回指针值的函数定义的一般形式是:返回指针值的函数定义的一般形式是: 类型标识符类型标识符 *函数名函数名(参数表参数表) 其中其中“*函数名函数名(参数表参数表)”是指针函数定义符。一是指针函数定义符。一定要区分指向函数指针变量与返回指针值的函数在定义定要区分指向函数指针变量与返回指针值的函数在定义上的不同,前者的指针变量名先与上的不同,前者的指针变量名先与“*”结合,表示是结合,表示是一个指针变量名,在和后面的一个指针变

61、量名,在和后面的“()()”结合,表示该指结合,表示该指针变量是指向函数的;后者的函数名先与针变量是指向函数的;后者的函数名先与“(参数表参数表) ”结结6.4.2 6.4.2 返回指针的函数返回指针的函数合,表示是一个函数,再与合,表示是一个函数,再与“*”结合,表示该函数的返回值结合,表示该函数的返回值是指针。例如:是指针。例如: int *search(int n,int a ) 说明说明search是一个返回是一个返回int型指针的函数,它有两个型指针的函数,它有两个int型形参型形参n和和a 。例例6-10 对于例对于例6-8,用返回指针值的函数完成找出有不及格,用返回指针值的函数完

62、成找出有不及格课程的学生并输出他们的学号及课程的学生并输出他们的学号及4门课成绩。门课成绩。 程序如下:程序如下:float *search(float (*p)4) int i; float *pt; pt=*(p+1); for (i=0;i4;i+) if (*(*p+i)60)pt=*p; return pt; main() static float score4= 70,52,68,89,88,74,85,96,64,55,53,78; float *prt; int i,j; for(i=0;i3;i+) prt=search(score+i); if (prt=*(score+i

63、) printf(No.%d score: ,i+1); for(j=0;j4;j+) printf(%5.2f ,*(prt+j); printf(n); 程序执行结果如下:程序执行结果如下:No.1 score: 70.00 52.00 68.00 89.00No.3 score: 64.00 55.00 53.00 78.00对本程序的说明:对本程序的说明:(1)search函数的返回值是指向实型数据的指针,形参是具函数的返回值是指向实型数据的指针,形参是具有有4个实型元素的一维数组的指针变量个实型元素的一维数组的指针变量p,功能是判断,功能是判断p所指所指的的4个实型元素有无小于个实型

64、元素有无小于60的数据,若有,则返回的数据,若有,则返回p所指的第所指的第1个元素的指针,若无,则返回个元素的指针,若无,则返回p的下一个指针所指的第的下一个指针所指的第1个个元素的指针。元素的指针。(2)主函数对每一个学生,循环调用)主函数对每一个学生,循环调用search函数,通过函数,通过search函数返回值的指针,判断该学生是否有不及格的成绩,函数返回值的指针,判断该学生是否有不及格的成绩,若有,则输出其学号及若有,则输出其学号及4门功课的成绩。门功课的成绩。(3)对于返回指针的函数,在定义是函数名前要有)对于返回指针的函数,在定义是函数名前要有“*”,但在调用时函数名前不需但在调用

65、时函数名前不需“*”。(4)对于二维数组的指针,要清楚哪些是行指针,哪些是行)对于二维数组的指针,要清楚哪些是行指针,哪些是行指针。本例中,指针。本例中,p、 p+1、 score+i都是行指针,都是行指针,pt、*(p+1)、*p+i、*(score+i)、prt、prt+j都是列指针,对行都是列指针,对行指针作指针作*运算就转换为列指针。运算就转换为列指针。6.5 6.5 字符指针字符指针 我我们们已已经经知知道道,C语语言言中中有有字字符符串串常常量量,但但没没有有字字符符串串变变量量,字字符符串串变变量量是是通通过过字字符符数数组组来来实实现现的的。本本节节给给出出字字符符串串的的指指

66、针针和和指指向向字字符符串串的的指指针针变变量量的的概概念念,用用字字符符指指针针方方便便、快快捷捷的的进进行行字字符串操作。符串操作。6.5 字符指针字符指针 6.5.1 字符串的指针字符串的指针6.5.2 字符数组和字符指针字符数组和字符指针 字符串除了可用字符数组实现外,也可用字符指针实现。字符串除了可用字符数组实现外,也可用字符指针实现。例例6-11 用两种不同的方式表示字符串。用两种不同的方式表示字符串。main() static char str1 =I love China!; char *str2=I love C language!; printf(%sn,str1); pr

67、intf(%sn,str2); 6.5.1 6.5.1 字符串的指针字符串的指针程序执行结果如下:程序执行结果如下: I love China! I love C language!例例6-12 用字符指针实现字符串的复制。用字符指针实现字符串的复制。main() char str1 =I love China!, str280,*p1,*p2; int i; p1=str1; p2=str2; for ( ; *p1!= 0;p1+,p2+ )p2=*p1; *p2=0; printf(string str1 is: %sn,str1); printf(string str2 is: %sn

68、,str2); 字符数组名和指向字字符数组名和指向字符串的指针变量也可符串的指针变量也可作为函数的参数,属作为函数的参数,属于于“地址传递地址传递”。例例6-13 用函数实现字符串的复制。用函数实现字符串的复制。(1)用字符数组作形参。用字符数组作形参。void copy_string(char from,char to) int i=0; while (fromi!=0) toi=fromi; i+; toi=0; (2)用字符数指针变量作形参。用字符数指针变量作形参。 void copy_string(char *from,char *to) while(*to+=*from+)!=0);

69、 例例6-14 用函数实现字符串的比较。用函数实现字符串的比较。int cmp_string(char *p1,char *p2) for (;(*p1!=0)&(*p1=*p2); p1+,p2+); return *p1-*p2; 请读者认真阅读分析请读者认真阅读分析,写出主函数并上机调试运行。主函写出主函数并上机调试运行。主函数中的实参可以用字符指针,也可用字符数组名。数中的实参可以用字符指针,也可用字符数组名。 6.5.2 6.5.2 字符数组和字符字符数组和字符指针变量的区别指针变量的区别 虽然用字符数组和字符指针变量都能实现字符串的存虽然用字符数组和字符指针变量都能实现字符串的存储

70、和运算,但它们二者之间是有区别的,不应混为一淡,储和运算,但它们二者之间是有区别的,不应混为一淡,主要有以下点:主要有以下点: (1)字符数组由若干个元素组成,每个元素中放一个字)字符数组由若干个元素组成,每个元素中放一个字符,而字符指针变量中存放的是地址(字符串第符,而字符指针变量中存放的是地址(字符串第1个字符的个字符的地址),并不是将字符串放到字符指针变量中。地址),并不是将字符串放到字符指针变量中。 (2)赋值方式。对字符数组只能对各个元素赋值,不能用)赋值方式。对字符数组只能对各个元素赋值,不能用以下办法对字符数组赋值。以下办法对字符数组赋值。 char str10; str=I l

71、ove you;而对字符指针变量,可以用下面方法赋值:而对字符指针变量,可以用下面方法赋值: char *a; a=I love you;(3)赋初值时,对以下变量的定义和赋初值:)赋初值时,对以下变量的定义和赋初值: char *a=I love China!; 等价于:等价于: char *a; a=I love China!;而对数组初始化时:而对数组初始化时: static char str14=I love China!;不能等价于:不能等价于: char str14; str =I love China!;即数组可以在定义时整体赋初值,但不能在赋值语句中整即数组可以在定义时整体赋初

72、值,但不能在赋值语句中整体赋值。体赋值。6.6 指针数组向指针的指针指针数组向指针的指针 6.6.1 指针数组指针数组6.6.2 指向指针的指针指向指针的指针 6.6.3 命令行参数命令行参数 指针变量同其它变量一样也可作为数组的元素,由指指针变量同其它变量一样也可作为数组的元素,由指针变量组成的数组称为指针数组,组成数组的每个元素都针变量组成的数组称为指针数组,组成数组的每个元素都是相同类型的指针。是相同类型的指针。 定义指针数组的形式为:定义指针数组的形式为: 类型名类型名 *数组名数组名常量表达式常量表达式; 其中其中“*数组名数组名常量表达式常量表达式”是指针数组说明符。是指针数组说明

73、符。一定要注意指针数组与指向一维数组的指针变量在定义形一定要注意指针数组与指向一维数组的指针变量在定义形式上的不同。如式上的不同。如 6.6.1 6.6.1 指针数组指针数组 int *p10; 说明说明p是指针数组,是指针数组,p先与先与“ ”结合,说明结合,说明p是数是数组,再与组,再与“*”结合,说明数组结合,说明数组p的元素是指向整型数据的元素是指向整型数据的指针。而的指针。而 int (*p)10; 说明说明p是指向由是指向由10个整型元素组成的一维数组的指个整型元素组成的一维数组的指针变量,针变量,p先与先与“*”结合,说明结合,说明p是一个指针变量,再是一个指针变量,再与与“ ”

74、结合,说明该指针变量指向由结合,说明该指针变量指向由10个整型元素个整型元素组成的一维数组的首地址。组成的一维数组的首地址。 指针数组的主要用途是表示二维数组,尤其是表示指针数组的主要用途是表示二维数组,尤其是表示字符串数组。用指针数组表示字符串数组的优点是每一字符串数组。用指针数组表示字符串数组的优点是每一个字符串可以具有不同的长度,使得对字符串数组的处个字符串可以具有不同的长度,使得对字符串数组的处理方便灵活。对若干个字符串进行字典排序是字符串的理方便灵活。对若干个字符串进行字典排序是字符串的最常用操作,如果用字符指针数组进行排序,就不必改最常用操作,如果用字符指针数组进行排序,就不必改动

75、字符串的位置,只需改动指针数组中各元素的指向动字符串的位置,只需改动指针数组中各元素的指向(即改变各元素的值,这些值是各字符串的首地址),(即改变各元素的值,这些值是各字符串的首地址),节省执行时间,又由于可以按每个字符串的具体长度分节省执行时间,又由于可以按每个字符串的具体长度分配存储空间,节省内存空间。配存储空间,节省内存空间。例例6-15 将若干字符串按字典顺序排序并输出。将若干字符串按字典顺序排序并输出。#include string.hvoid bubble_sort(char *str,int n) char *temp; int i,j,flag; for (i=0;in-1;i

76、+) flag=1; for (j=0;j0) temp=strj;strj=strj+1;strj+1=temp; flag=0; if (flag)return; main() char *name=China,Japan,Britain,France,Iraq,America,Russia,Canada; bubble_sort(name,8); print_str(name,8); void print_str(char *str,int n) int i; for (i=0;in;i+) printf(%sn, stri); 程序执行结果如下:程序执行结果如下:AmericaBrit

77、ainCanadaChinaFranceIraqJapanRussia说明:说明:(1)bubble_sort函数采用的是冒泡排序法。冒泡法排序属于交函数采用的是冒泡排序法。冒泡法排序属于交换排序,基本思想是比较相邻的元素,如不符合顺序,就进行换排序,基本思想是比较相邻的元素,如不符合顺序,就进行交换,直到所有相邻的元素都符合顺序为止。算法实现需要交换,直到所有相邻的元素都符合顺序为止。算法实现需要n-1趟相邻元素的比较,每趟都从第趟相邻元素的比较,每趟都从第1个元素开始与其后的元素个元素开始与其后的元素进行比较,这样,较小的数不断向前移动,本趟最大的数移到进行比较,这样,较小的数不断向前移动

78、,本趟最大的数移到最后(第最后(第n-i+1个位置)个位置),俗称俗称“冒泡冒泡”。(2)由于要用到字符串的比较函数由于要用到字符串的比较函数strcmp,故在文件开头用,故在文件开头用#include string.h命令作了头文件包含。命令作了头文件包含。(3) print_str函数中的输出表达式函数中的输出表达式stri也可写成也可写成*(str+i)。 指向指针数据的指针变量,简称为指向指针的指针。指向指针数据的指针变量,简称为指向指针的指针。例例6-16 指向指针的指针的例子。指向指针的指针的例子。main() int a=1000,*p,*p_p; p=&a; p_p=&p; p

79、rintf(%o %on,a,*a); printf(%o %o %on,*p,p,&p); printf(%o %o %o %on,*p_p,*p_p,p_p,&p_p);6.6.2 6.6.2 指向指针的指针指向指针的指针程序执行结果如下:程序执行结果如下:1750 177714177714 177716177714 177716 177720说明,本例中说明,本例中a是整型变量是整型变量a(八进制的值是(八进制的值是1750),),p是是指针指针,p_p是指针的指针。内存分配示意图见图是指针的指针。内存分配示意图见图6-5。内存单内存单元地址元地址177714177716 177720内

80、存单内存单元值元值1750177714 177716变量名变量名变量变量a指针指针p 指针指针p_p图图 6-5 对于例对于例6-15,如果要使用指针的指针作为函数的形参,如果要使用指针的指针作为函数的形参,就需将两个函数的形参就需将两个函数的形参str定义为定义为 char *str; 函数中相应的表达式函数中相应的表达式strj、strj+1和和stri改写成改写成*(str+j)、*(str+j+1)和和*(str+i)即可,请读者上机验证。即可,请读者上机验证。 前面的前面的main函数都没有参数,实际上,函数都没有参数,实际上,main函数可函数可以有参数,例如:以有参数,例如: m

81、ain(int argc,char *argv )argc和和argv就是就是main函数的形参。其中,函数的形参。其中,argc是程序所是程序所调用的命令行参数的个数(包括可执行文件名),调用的命令行参数的个数(包括可执行文件名),argv是是个指针数组,它的每个元素指向命令行的每个字符串,如个指针数组,它的每个元素指向命令行的每个字符串,如argv0一定指向可执行文件名。一定指向可执行文件名。 6.6.3 6.6.3 命令行参数命令行参数当处于操作命令状态下,输入当处于操作命令状态下,输入main所在的文件名所在的文件名(经过经过编译、连接后得到的可执行文件名编译、连接后得到的可执行文件名

82、),系统就调用,系统就调用main函数。由于函数。由于main函数有形参,就必须在命令行中包括函数有形参,就必须在命令行中包括命令名和需要传给命令名和需要传给main函数的参数。命令行的一般形函数的参数。命令行的一般形式为式为 命令名命令名 参数参数1 参数参数2参数参数n命令名和各参数之间用空格分隔。命令名是命令名和各参数之间用空格分隔。命令名是main所在所在的文件名。的文件名。例例6-17 命令行参数的例子。命令行参数的例子。#include stdio.hmain (int argc,char *argv ) int i; for(i=1;iargc;i+) printf(%s%s,a

83、rgvi,(iy?x:y; int min(int x,int y) return xy?x:y; main(int argc,char *argv) int a,b; char *op if(argc4)exit(0); a=atoi(argvl);b=atoi(argv2); op=argv3;if(strcmp(op,max)=0)printf(Thesofsandsis:%dn,argv3,argv1,argv2,max(a,b);else if(strcmp(op,”min”)=0) printf(Thesofsandsis:%dn,argv3,argv1,argv2,min(a,b

84、);else printf(op should be max or minn); 程序生成程序生成abc.exe后,设命令行为:后,设命令行为:abc 20 60 min则输出结果为则输出结果为The min of 20 and 60 is:206.7 本章小结本章小结 6.7.2 与指针相关的运算小结与指针相关的运算小结 6.7.1 指针类型小结指针类型小结6.7.3 使用指针的利与弊使用指针的利与弊表表6-3给出了不同类型的指针的定义及其含义给出了不同类型的指针的定义及其含义,以表对照区别。以表对照区别。6.7.1 6.7.1 指针类型小结指针类型小结表6-3指针类型指针类型 定定 义义含

85、含 义义变量的指针变量的指针 int *p;p为指向整型数据的指针变量为指向整型数据的指针变量数组的指针数组的指针int (*p)n;p为指向含有为指向含有n个整型元素的一维数组的指针变量个整型元素的一维数组的指针变量函数的指针函数的指针int (*p)();p为指向函数的指针,该函数的返回值为整型为指向函数的指针,该函数的返回值为整型指针函数指针函数int *f() f为返回指针值的函数,该指针指向整型数据为返回指针值的函数,该指针指向整型数据指针数组指针数组int *pn;p是一个指针数组,它由个指向整型数据的指针是一个指针数组,它由个指向整型数据的指针组成组成字符指针字符指针char *

86、str;str为指向字符型数据的指针变量为指向字符型数据的指针变量指针的指针指针的指针int *p; p为指向整型数据的指针的指针变量为指向整型数据的指针的指针变量1指针的基本运算有:指针的基本运算有:&,*,+,-,-,比较,赋值,比较,赋值运算,要弄清它们之间的复合运算,如运算,要弄清它们之间的复合运算,如*p+,(*p)+等的意义。等的意义。2. 定义指针时,要注意指针运算符定义指针时,要注意指针运算符“*”与下标运算符与下标运算符“ ”及函数运算符及函数运算符“()()”的结合次序,的结合次序,“ ”及及“()()”是高于是高于“*”运算的。运算的。3. 不同的指针类型之间不能直接赋值

87、,需要进行类型转换。不同的指针类型之间不能直接赋值,需要进行类型转换。例如例如 6.7.2 6.7.2 与指针相关的运算小结与指针相关的运算小结 int *p1; float *p2;则则p1、p2间不能直接赋值,但可先转换,后赋值,如间不能直接赋值,但可先转换,后赋值,如 p1=(int *)p2;或或 p2=(float *)p1;都是合法的赋值语句。都是合法的赋值语句。 使用指针的优点可以提高程序效率;在调用函数使用指针的优点可以提高程序效率;在调用函数时变量改变了的值能够为主调函数使用,即可以从函时变量改变了的值能够为主调函数使用,即可以从函数调用得到多个可改变的值;可以实现动态存储分

88、配。数调用得到多个可改变的值;可以实现动态存储分配。但是同时应该看到,但是同时应该看到,C语言在指针的使用上非常灵活,语言在指针的使用上非常灵活,对熟练的程序人员来说,可以利用它编写出颇有特色对熟练的程序人员来说,可以利用它编写出颇有特色的、质量优良的程序,实现许多用其他高级语言难以的、质量优良的程序,实现许多用其他高级语言难以实现的功能,但也十分容易出错,而且这种错误往往实现的功能,但也十分容易出错,而且这种错误往往难以发现。由于指针运用的错误甚至会引起使整个程难以发现。由于指针运用的错误甚至会引起使整个程序遭受破坏,比如由于未对指针变量序遭受破坏,比如由于未对指针变量p赋值就向赋值就向“p赋赋值这就可能破坏了有用的单元的内容。如果使值这就可能破坏了有用的单元的内容。如果使6.7.3 6.7.3 使用指针的利与弊使用指针的利与弊用指针不当,特别是赋予它用指针不当,特别是赋予它个错误的值时,会成为个错误的值时,会成为一个极其隐蔽的、难以发现和排除的故障。因此,使一个极其隐蔽的、难以发现和排除的故障。因此,使用指针要十分小心谨慎,要多上机调试程序,以弄清用指针要十分小心谨慎,要多上机调试程序,以弄清一些细节,并积累经验。一些细节,并积累经验。

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 医学/心理学 > 基础医学

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号