大学实用C语言程序设计教程-陈建铎-大学教学资料课件PPT
收藏
资源目录
压缩包内文档预览:
编号:21835837
类型:共享资源
大小:13.46MB
格式:ZIP
上传时间:2019-09-06
上传人:QQ24****1780
认证信息
个人认证
王**(实名认证)
浙江
IP属地:浙江
25
积分
- 关 键 词:
-
大学
实用
语言程序设计
教程
陈建
教学
资料
课件
ppt
- 资源描述:
-
大学实用C语言程序设计教程-陈建铎-大学教学资料课件PPT,大学,实用,语言程序设计,教程,陈建,教学,资料,课件,ppt
- 内容简介:
-
指针是C语言的个重要特色,是C语言的精华所在。正是丰富的指针运算功能才使得C语言是目前最常用、最流行的面向过程的结构化程序设计语言。正确而灵活地运用指针,能有效地表示复杂的数据结构、方便地使用数组和字符串;可以在函数间进行数据传递;可以直接处理内存地址、动态分配内存等。熟练、灵活的使用指针,可以使程序简洁、紧凑、高效。 本章首先给出指针的概念,然后分别讲述变量的指针、数组的指针、函数的指针、指针数组、字符指针及指针的指针等,并配有一定数量的例题,加深理解。 第6章 指针第6章 指针6.1 内存数据的指针与指针变量6.2 指针变量的定以及指针运算 6.3 数组元素的指针与数组的指针 6.4 函数的指针和返回指针的函数 6.5 字符指针6.6 指针数组与指向指针的指针6.7 本章小结 6.1 内存数据的指针与指针变量 指针既是C语言的重点,也是C语言的难点之一。简单的地说,指针就是内存单元的地址。为深刻理解指针的概念,必须弄清楚内存的概念以及数据在内存中是如何存储的,又是如何读取的。 我们都知道,在计算机的硬件构成中,主机是由运算器、控制器和存储器组成,前两者合在一起称为中央处理器,简称CPU,而存储器又分为内部存储器和外部存储器,简称内存和外存,所有数据只有存放在内存中计算机才能进行处理和运算。内存计量的基本单位是字节,它是进行分配和读取的最小单位,每个字节由8个二进制位(bit)组成,一个字节就是一个内存单元。整个内存空间是一维的,每个字节都有一个唯一的序号,称为内存单元的地址,比如对一个1Mb的内存,其内存单元的地址分别为0,1,2,3,。 任何计算机程序只有存贮在内存中才能被执行。操作系统要占用一些计算机内存空间,每个应用程序也要占用计算机内存空间。按照面向过程的结构化程序设计方法,程序代码和程序要处理的数据是分开存贮的。所以,一个程序在内存中要占两部分存储空间:数据部分和指令代码部分。 此处只考察数据段在内存中的存贮情况。当C程序中定义一个变量时,编译系统划分一定数目的存贮单元来存贮那个变量,存贮单元的数目由变量的类型确定,例如,一般微机使用的C语言系统为整型变量分配2个字节,对实型变量分配4个字节,对字符型变量分配1个字节等,若变量分配的不是1个字节,此时以变量分配的第一个字节的地址作为该变量存储地址,这就是内存数据的指针,编译系统把这几个存贮单元与变量名联系起来。如有一整型变量,变量名是n,值是999,占用的存贮单元是3000和3001两个字节,则变量n的内存地址是3000。 一定要清楚变量的地址与变量的值不是一回事,变量的地址是由编译系统按一定规则进行分配的,一经分配就固定不变,变量的值在程序运行过程中是可以改变的,用户需要关心的是变量的当前值,而不必关心变量的地址,即变量存储单元。 当程序引用这个变量时,可通过变量名自动地访问相应的存贮单元,当然程序也可以通过该变量的地址来访问这些存贮器单元。按变量地址存取变量值的访问方式称为“直接访问”方式。如对上面提到的变量n,为了得到其值,可直接读出3000和3001两个字节的值即可,赋值语句n=456;将变量n的值改为456,系统只需把456写到3000和3001两个字节中即可。 在C语言中,可以定义一种特殊的变量,它是专门用来存放变量的存储单元的地址,称为指针变量。这样对变量的访问可以采用另一种称之为“间接访问”的方式,例如,我们可先定义一个存放整型变量的地址的指针变量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所示。图 6-1 如果要将变量n的值改为1234,则用赋值语句n=1234;和*n_prt=1234;的效果是一致的,前者是直接访问,而后者是间接访问。其中符号“&”和“*”是两个重要的指针运算符“取地址”和“取值” 运算符。 需要说明的是,指针类型是对所有类型的指针的总称,指针的类型是指针所指对象的数据类型。例如,n_prt是指向整型变量的指针,简称整型指针。除各种基本类型的指针外,允许定义指向数组的指针、指向函数的指针、指向结构体和共用体的指针以及指向各类指针的指针。在C语言中只有指针被允许用来存放地址的值,其它类型的变量只能存放该类型的数据。6.2 指针变量的定义及指针运算6.2.1 指针变量的定义 6.2.2 指针变量的运算6.2.3 指针变量作为函数的参数 变量的指针就是变量的地址,专门用来存放变量地址的变量称为指针变量。C语言规定所有变量在使用前必须定义,指针变量也不例外,定义指针变量的一般形式是: 类型标识符 *指针变量名; 这里,类型标识符说明该指针变量用来存放哪一种类型的变量的地址,可以是基本类型,也可以是构造类型,如结构体类型、指针类型等。指针变量名前的“*”不可少,它表明该变量是指针变量。例如 6.2.1 指针变量的定义 int i ,j, k; float x, y; int *p1, *p2,*p3; float *p4,*p5; 以上说明语句,定义了3个指向整型数据的指针变量和2个指向实型数据的指针变量(此时,它们并没有指向某一具体变量)。既然指针变量存放的是变量的地址,它的值就不允许用户随意指定,这样就会造成混乱,指针变量的值可以通过取地址运算和地址赋值运算来取得。如 p1=&i; p2=&j; p3=p2; p4=&x; p5=p4;此时,我们称指针变量p1指向变量i ,指针变量p2和p3同时指向变量j,指针变量p4和p5同时指向变量x。但是语句 p2=&y; p5=p1; p3=2800;都是错误的。因为一个指针变量只能指向同一个类型的变量,只能把指针(地址)赋给指针变量。同普通变量一样,指针变量的赋初值也可在定义时进行。如 int num =5, *prt ; prt=#与 int num =5, *prt=#是等效的。 1&和*运算(1)& 取地址运算符。(2)* 取值运算符。&和*运算是同级运算,结合性是“从右至左”,运算级别低于( )、 、+、- -、.等运算,高于算术、位移、关系、赋值等运算。2+和- -运算指针变量的+和- -运算与指针变量的类型有关,确切地说,是与指针变量的类型所占用的存储字节的个数有关。6.2.2 指针变量的运算假如指向变量的指针变量pointer的值是4000,若pointer指向的是整型变量a,则分别执行pointer+和pointer-后,pointer的值分别是4002和3998;若pointer指向的是实型变量,则分别执行pointer+和pointer-后,pointer的值分别是4004和3996。但是,需要注意,变化后指针变量所指单元可能没有值,也可能不是所期望的值,这一点应引起重视。3指针的比较运算同类型的指针变量可以作比较运算、差运算,不能做加运算。 以下给出一些指针运算的结论:*&a与a等价&*pointer与pointer等价(*pointer)+与a+等价*(pointer+)即*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 %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 177720 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+是等价的。第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单元的值无意义。第6行输出的不是2和-2,而是1和-1,说明p1指向p2的下一个存储单元,此时意义不大,后面将会看到,当两个指针指向同一数组的元素时,指针的差才有意义。我们还可以看到,变量a、b、p1、p2的地址是始终不变的。 上一章已经提到,指针变量也可作为函数的参数,此时函数的实参与形参之间是地址传递。 例6-2 输入两个整数a,b, 按先大后小的顺序输出a和b。 程序1:不用子函数,在主函数中交换指针变量的的值。 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); 程序执行结果如下: input 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,*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, 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; 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=5 a=10 b=50 *pa=10 *pb=50 程序执行结果没有完成预期目的。因为当ab时,函数swap把指针变量pa和pb的值做了交换,在swap函数返回前,形参p1指向b=50,p2指向a=10,但在swap函数返回时,p1和p2的值并不能传递给实参pa和pb。因为C语言中实参变量和形参变量之间的数据传递是单向的“值传递”方式。指针变量作函数参数也要遵循这一规则。调用函数不可能改变实参指针变量的值,但可以改变实参指针变量所指变量的值。交换前后的情况见图6-4。10a50b10a50b&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)swap(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 数组元素的指针 与数组的指针 数组是由若干同类型的数据元素组成的构造类型,在内存中占用一段连续的存储单元。指针变量既然可以指向变量,当然也可以指向数组元素,所谓数组元素的指针就是数组元素的首地址,数组的指针就是数组的首地址,它也是数组的第1元素的地址。引入指针后,对数组元素的引用可以用下标法,也可以用指针法,即通过指向数组元素的指针找到所需的元素。使用指针法访问数组元素能使目标程序占内存少且运行速度快。6.3 数组元素的指 针与数组的指针 6.3.2 数组的指针6.3.3 多维数组的指针6.3.4 指向由m个元素组成的 一维数组的指针变量6.3.1 数组元素的指针1. 指向数组元素的指针变量 数组中的每一元素要占用一段存储单元,其第1个字节的地址就是该数组元素的地址。如果定义一个指向数组元素的指针变量,就可以用指针变量访问数组元素。定义形式与定义指向变量的指针变量相同。如 int array20,num; int *p; 此时p是一个只能指向整型数据的指针变量。可以令 p=&array5;6.3.1 数组元素的指针则p指向数组元素array5。也可以令 p=#则p指向整型变量num。同样地,可以在定义指向数组元素的指针变量同时,对其赋初值。如 int array20,*prt=&array0;和 int array20,*prt=array;是等效的,因为array既是数组的地址,也是第1个数组元素 array0的地址。2. 用指针变量访问数组元素 用指向数组元素的指针变量访问数组元素可以提高程序的效率。设有语句 int a 20,*p=&a 0;则 (1) p+i和a+i都表示ai的地址,即它们都指向数组元素ai。 (2) *(p+i)和*(a+i) 都是p+i或a+i所指向的数组元素ai。 事实上,编译程序对数组元素ai就是处理成*(a+i),即按数组首元素的地址加上相对位移量得到要找的元素的地址,然后找出该单元中的内容。这也是C语言把数组的最小下标规定为0的原因。在运算符表中,下标运算符 实际上是变址运算符,即将ai按a+i计算地址,然后找出此地址单元中的值。 (3) 指向数组的指针变量也可以带下标,如*(p+i)也可写成 pi,二者是等价的。 (4) 虽然p和a都是指针,但p的值可变,而a的值不可变,即p可指向任一数组元素,而a始终指向数组元素a0。如p+是合法的,而a+是非法的。 根据以上可知,引用一个数组元素,可以用下标法(如ai形式)和指针法(如*(a+i)或*(p+i)形式)。例6-4引用一个数组元素的例子。main() 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+输出数组元素,结果相同。 数组的指针就是数组首元素的地址。用数组名作为函数的参数,实参数组名代表该数组首元素的地址,而形参是用来接收从实参传递过来的数组首元素的地址。因此,形参应该是一个指针类型的量,可以是指针变量也可以是数组名。实际上,C编译系统就是将形参数组名作为指针变量来处理的。 实参数组和形参数组各元素间并不存在“值传递”,在函数调用时,形参数组并不开辟新的存储单元,而是以实参数组的首地址作为形参数组的首地址,使形参数组和实参数组共享一段存储空间。正是共享的缘故,才使得函数中对形参数组元素的改变就是对实参数组元素的改变,函数调用结束后,改变的结果得以保留,可以得到多个改变后的值。6.3.2 数组的指针例6-5 将数组a中n个整数按相反顺序存放。 题目分析:在例5-6和例5-14中已熟悉了数组元素反顺序存放的算法,这里通过本题加深对数组的指针、数组元素的指针和数组名作为函数参数的参数传递的了解。程序如下: 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(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改成指针变量。改动后的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); 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)实参用数组名,形参用指针变量;(3)实参用指针变量,形参用数组名;(4)实参用指针变量,形参用指针变量。 数组是C语言的一个构造类型,其元素可以是C语言的任何类型,包括数组本身。也就是说,数组可以作为另一个数组的数组元素。这样,多维数组的问题就迎忍而解了,在C语言中,数组在实现方法上只有一维的概念,多维数组被看成以下一级数组为元素的数组。 设有一个二维数组的定义为: static int a24=1,3,5,7,2,4,6,8; 表面上看,a是一个二维数组名,我们也可以将它看成是一个一维数组名。它包含两个数组元素,分别为a0和a1。6.3.3 多维数组的指针每个数组元素又包含四个元素,例如,数组a0包含四个元素,分别为:a00、a01、a02和a03,数组a1包含四个元素,分别为:a10、a11、a12和a13。a0和a1虽然没有单独地、显式地定义,它们却可以被认为是数组名,是数组在内存中的首地址,这一点与数组名a一样,但与a的类型不同,也就是数组元素的类型不同。a0和a1数组的元素类型为整型数,而a数组的元素类型为整型数组。 假设数组a在内存中的分配情况如表6-1所示。 表 6-1可以看到对于数组a来说,它所占用的内存空间是连续的。如果我们将a视为一维数组的话,那么它的两个数组元素a0和a1所占用的内存空间也是连续的,此时每个数组元素占用8个内存单元。当然如果将a视为二维数组的话,它的8个数组元素所占用的内存空间也是连续的,此时每个数组元素占用2个内存单元。另外,二维数组是按行优先次序存储的。 C语言程序中数组及其数组元素的表示形式有很多。为了更清楚地说明,我们可以上面定义把二维数组a看成是一个两行四列的形式。这样对于二维数组可以认为a为首行地址(即第0行地址),而a+1为第1行地址;a0为首行首列地址,而a0+1为第0行第1列地址。 a13,*(a1+3),*(*(a+1)+3)表示同一个元素,值为8。 具体说明见表6-2。表 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,*p); 程序执行结果如下: 1 3 5 7 2 4 6 810 20 30 40 既然用指针变量来存放列地址,那么同样可以用指针变量来存放行地址,定义存放行地址的指针变量的形式为: 类型名 (*指针名)数组长度; 约束行指针类型的条件有两个,一是它所指向数组的类型;一是每行的列数。如语句 int (*p)4; 说明p是一个指针变量,它指向包含4个整型元素的一维数组。注意*p两侧的括号不可缺少,如果写成*p4,由于6.3.4 指向由m个元素组成的 一维数组的指针变量方括号 运算级别高,则p先与4结合,是数组,然后再与前面的*结合,*p4是指针数组(见6.6节)。 *p有4个元素(*p)0、(*p)1、(*p)2和(*p)3,每个元素为整型,也就是p所指的对象是有4个整型元素的数组,即p是行指针,此时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 多维数组的行指针。 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。 多维数组的地址也可作为函数参数传递,在用指针变量作形参以接受实参数组名传递来的地址时,有两种方法:用指向变量的指针变量;用指向一维数组的指针变量。 例6-8 有一个班,3个学生,各学4门课,计算总平均分数,输出第n个学生的成绩,找出有不及格课程的学生并输出他们的4门课成绩。 题目分析:可用一个3行4列的二维数组存储题目给出的数据,设计average函数用来求总平均成绩,outdata函数用来找出并输出第个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 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 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=-10 C语言中函数可以返回除数组、共用体变量和函数以外的任何类型数据和指向任何类型的指针。返回指针值的函数定义的一般形式是: 类型标识符 *函数名(参数表) 其中“*函数名(参数表)”是指针函数定义符。一定要区分指向函数指针变量与返回指针值的函数在定义上的不同,前者的指针变量名先与“*”结合,表示是一个指针变量名,在和后面的“()”结合,表示该指针变量是指向函数的;后者的函数名先与“(参数表) ”结6.4.2 返回指针的函数合,表示是一个函数,再与“*”结合,表示该函数的返回值是指针。例如: int *search(int n,int a ) 说明search是一个返回int型指针的函数,它有两个int型形参n和a 。例6-10 对于例6-8,用返回指针值的函数完成找出有不及格课程的学生并输出他们的学号及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) 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个实型元素有无小于60的数据,若有,则返回p所指的第1个元素的指针,若无,则返回p的下一个指针所指的第1个元素的指针。(2)主函数对每一个学生,循环调用search函数,通过search函数返回值的指针,判断该学生是否有不及格的成绩,若有,则输出其学号及4门功课的成绩。(3)对于返回指针的函数,在定义是函数名前要有“*”,但在调用时函数名前不需“*”。(4)对于二维数组的指针,要清楚哪些是行指针,哪些是行指针。本例中,p、 p+1、 score+i都是行指针,pt、*(p+1)、*p+i、*(score+i)、prt、prt+j都是列指针,对行指针作*运算就转换为列指针。6.5 字符指针 我们已经知道,C语言中有字符串常量,但没有字符串变量,字符串变量是通过字符数组来实现的。本节给出字符串的指针和指向字符串的指针变量的概念,用字符指针方便、快捷的进行字符串操作。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); printf(%sn,str2); 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,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); 例6-14 用函数实现字符串的比较。int cmp_string(char *p1,char *p2) for (;(*p1!=0)&(*p1=*p2); p1+,p2+); return *p1-*p2; 请读者认真阅读分析,写出主函数并上机调试运行。主函数中的实参可以用字符指针,也可用字符数组名。 6.5.2 字符数组和字符指针变量的区别 虽然用字符数组和字符指针变量都能实现字符串的存储和运算,但它们二者之间是有区别的,不应混为一淡,主要有以下点: (1)字符数组由若干个元素组成,每个元素中放一个字符,而字符指针变量中存放的是地址(字符串第1个字符的地址),并不是将字符串放到字符指针变量中。 (2)赋值方式。对字符数组只能对各个元素赋值,不能用以下办法对字符数组赋值。 char str10; str=I love 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!;即数组可以在定义时整体赋初值,但不能在赋值语句中整体赋值。6.6 指针数组向指针的指针 6.6.1 指针数组6.6.2 指向指针的指针 6.6.3 命令行参数 指针变量同其它变量一样也可作为数组的元素,由指针变量组成的数组称为指针数组,组成数组的每个元素都是相同类型的指针。 定义指针数组的形式为: 类型名 *数组名常量表达式; 其中“*数组名常量表达式”是指针数组说明符。一定要注意指针数组与指向一维数组的指针变量在定义形式上的不同。如 6.6.1 指针数组 int *p10; 说明p是指针数组,p先与“ ”结合,说明p是数组,再与“*”结合,说明数组p的元素是指向整型数据的指针。而 int (*p)10; 说明p是指向由10个整型元素组成的一维数组的指针变量,p先与“*”结合,说明p是一个指针变量,再与“ ”结合,说明该指针变量指向由10个整型元素组成的一维数组的首地址。 指针数组的主要用途是表示二维数组,尤其是表示字符串数组。用指针数组表示字符串数组的优点是每一个字符串可以具有不同的长度,使得对字符串数组的处理方便灵活。对若干个字符串进行字典排序是字符串的最常用操作,如果用字符指针数组进行排序,就不必改动字符串的位置,只需改动指针数组中各元素的指向(即改变各元素的值,这些值是各字符串的首地址),节省执行时间,又由于可以按每个字符串的具体长度分配存储空间,节省内存空间。例6-15 将若干字符串按字典顺序排序并输出。#include string.hvoid bubble_sort(char *str,int n) char *temp; int i,j,flag; for (i=0;in-1;i+) 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); 程序执行结果如下:AmericaBritainCanadaChinaFranceIraqJapanRussia说明:(1)bubble_sort函数采用的是冒泡排序法。冒泡法排序属于交换排序,基本思想是比较相邻的元素,如不符合顺序,就进行交换,直到所有相邻的元素都符合顺序为止。算法实现需要n-1趟相邻元素的比较,每趟都从第1个元素开始与其后的元素进行比较,这样,较小的数不断向前移动,本趟最大的数移到最后(第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; printf(%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 指向指针的指针程序执行结果如下:1750 1
- 温馨提示:
1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
2: 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
3.本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

人人文库网所有资源均是用户自行上传分享,仅供网友学习交流,未经上传用户书面授权,请勿作他用。