![指针引用与动态内存分配_第1页](http://file3.renrendoc.com/fileroot_temp3/2022-1/19/6fb922f0-e6c8-4c62-a2be-d5e8f5c4139b/6fb922f0-e6c8-4c62-a2be-d5e8f5c4139b1.gif)
![指针引用与动态内存分配_第2页](http://file3.renrendoc.com/fileroot_temp3/2022-1/19/6fb922f0-e6c8-4c62-a2be-d5e8f5c4139b/6fb922f0-e6c8-4c62-a2be-d5e8f5c4139b2.gif)
![指针引用与动态内存分配_第3页](http://file3.renrendoc.com/fileroot_temp3/2022-1/19/6fb922f0-e6c8-4c62-a2be-d5e8f5c4139b/6fb922f0-e6c8-4c62-a2be-d5e8f5c4139b3.gif)
![指针引用与动态内存分配_第4页](http://file3.renrendoc.com/fileroot_temp3/2022-1/19/6fb922f0-e6c8-4c62-a2be-d5e8f5c4139b/6fb922f0-e6c8-4c62-a2be-d5e8f5c4139b4.gif)
![指针引用与动态内存分配_第5页](http://file3.renrendoc.com/fileroot_temp3/2022-1/19/6fb922f0-e6c8-4c62-a2be-d5e8f5c4139b/6fb922f0-e6c8-4c62-a2be-d5e8f5c4139b5.gif)
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、6.1 选择排序算法 1第六章指针,引用与动态内存分配在第四章,我们曾引入数组类型,它与本章介绍的指针和引用类型是C+语言提供的三种导出类型,正确灵活地使用数组,指针和引用类型,是设计高质量的C+程序所必经掌握的技术。结构在只有数据成员时,也是一种导出数据类型,不过,语言允许用户为结构设计函数成员,实际上是用户为该结构类型设计的运算,因此,结构也是用户定义的类或类型,将在下一章介绍。C+程序中所处理的数据主要以变量(和对象)的形式出现。每个变量有两个最主要的属性,那就是变量的内容和地址。例如: int a=3,b=5,c;c=a+b;在上面语句中,变量a,b,c已被赋值。在它们被重新赋值或被释
2、放之前,变量名a,b,c就代表着它们的内容,即整型数3,5,8。由变量a,b,c参加的任何运算,都是对它们的值3,5,8进行的运算。另一方面,C+语言也为用户对于变量所占空间的地址提供了进行操作的机制,这就是指针类型和引用类型。指针和引用不是一种独立的数据类型,而是一种导出数据类型。指针类型也是语言和语言的重要类型,而引用类型是语言中新的重要类型,在语言和语言等一些新的语言中,引用类型取代了指针类型,因此,两者的使用都应该熟练掌握。我们首先通过实例来说明指针的使用。选择排序算法排序的任务是把已经存在一个数组里的n个数按从大到小的顺序排列,可以采用多种不同的方法实现,选择排序算法的思路简单,容易
3、理解,每次总是从无序的序列中选出最大者,交换到序列的左端,于是,无序的序列越来越短,经过步,达到排序的目的。程序program6_1的主要部分是介绍实现选择排序算法的函数void ssort(float *,int ),在阅读下面的程序时,应特别注意指针类型变量和函数参数的使用:/program6_1.cpp#include<iostream.h>#include<stdlib.h> #include<iomanip.h>void ssort(float *, int );void main(void)int i, seed, n=20;cout<&l
4、t;endl<<"seed=" ;cin>>seed;cout<<endl;srand(seed);float list20, *pf;for(i=0; i<n; i+)listi = rand( );cout<<setw(8)<<listi;if (i+1)%8=0)cout<<endl;i=0; cout<<endl;pf=&list0;ssort (pf,n);while ( i<n ) cout<<setw(8)<<listi;i+;if
5、(i % 8 = 0)cout<<endl;cout<<endl;void swap1(float *a, float *b) float temp;temp = *a;*a = *b;*b = temp;6.1 选择排序算法 3void ssort (float *a, int m)int i, j, index;float elem;for (i=0; i<m-1; i+)elem = *(a+i);index = i;for (j=i+1; j<m; j+)if (*(a+j)>elem)elem = *(a+j);index = j;swap1
6、(a+i, a+index);运行结果:seed=652321339 28822 26220 8712 18120 1280 27491 86477137 2030 24101 20505 4452 26942 10989 2991927130 20996 17227 1355929919 28822 27491 27130 26942 26220 24101 2133920996 20505 18120 17227 13559 10989 8712 86477137 4452 2030 1280程序说明:这个程序重点是介绍函数ssort( ) 和swap1( ) 的设计,应特别注意指针变量、
7、函数()的指针类型参数和函数()的指针类型参数,的说明和使用方法。主函数做了三件事:)为长度为的数组输入个随机数,作为排序算法处理的对象,程序中取,是为了显示输出结果方便,也可取或更大,实际输入的值是整数也是为了显示清楚。利用库函数()产生伪随机数形成无序数组,由用户输入一个随机数(例如)作为“”可使无序数组的个数的随机性较好。)调用函数()进行排序。)把经过排序的数组的值输出。函数swap1( )的定义中使用了指针类型的参数。参数a,b是float型的指针变量,即它们的值应是浮点型变量的地址。在swap1( ) 的调用语句中,实参a+i, a+index, 其中a为float 型的指针,i,
8、 index为整型变量,C+ 语言允许指针变量+/-整数,其结果仍为指针。即a+i, index应表示数组List 中a指向的元素后面的元素变量的地址。在函数swap1( )中使用了*a和*b,这里符号*不是乘法运算符,而是表示指针变量(a或b)所指向的那个变量。例如:int n=4, *p;p=&n;*p+;表示有整型变量n,和整型指针变量p,用&n表示变量n的地址,p=&n使指针p指向变量n,而这时*p正是表示变量n,*p+相当于n+。由此可以看出,&和*是一对用于指针操作的互逆的单目运算符,(在这里&不是“引用”的意思)。&n表示变量n的地
9、址,而*p表示指针p指向的变量或该变量的值。对于函数swap1(float *a,float *b),读者可与上一章中介绍的swap(int &a, int &b)函数作一比较,虽然它们都达到交换两个变量内容的目的,但采用的方式却是不同的。在swap1( )中有两个指针型参数,属于赋值形参,在调用时创建两个新的指针变量a和b,把实参表达式计算的结果地址赋给a和b,从而使指针a和b指向相应的变量。而在swap( )中形参a,b为引用型,它是在调用时直接由实参的变量代替a,b参加swap( )函数的函数体操作。函数ssort( )是一个用于对m个浮点数组进行排序的函数,其参数为 f
10、loat型指针和int 型整数。前者指明数组的首地址,后者为数组中元素的个数,执行结果是把这个数组中的浮点数按从大到小的顺序排列好。按照C+语言的规定,数组名list除了作为名字之外,它还可表示该数组的首地址,即可以用list直接表示&list0。因此,行可以用下面一个调用语句取代:ssort(list,n)其效果完全相同。函数ssort(tist,n)的函数体是具体完成排序的过程,请注意如何表示数组的各个元素。从这里可以更清楚地了解到:程序中说明的数组list20,实际上是n(=20)个float型变量,它们除可以用下标变量list0,list1,list19表示之外,也可以用*li
11、st,*(list+1),*(list+19)来表示。指针可以和整数做加减法,这一点已在上6.2 导出数据类型(2),指针(Pointer) 5文指出,指针变量做加法要小心,C/C+的指针操作有些“过于自由”了。把个数排好次序可以有许多种不同的算法,这个函数是每次把尚未排好的元素中的最大元素选出,移到左端,最终形成从大到小的排列,故被称为选择排序算法。下节介绍有关指针类型的语法规则。指针()类型指针变量说明指针类型的变量说明格式为:类型名指针变量名初值;类型名:任一基本类型名,基本类型的派生类型名,用户定义的类枚举类型结构及联合类型名。类型名为void时,称为不确定类型的指针类型。类型名也可以
12、是由类型名表示的指针类型名,这时称为多级指针(指针类型的指针)。符号:表示其后说明的变量为指针变量(这里的”不是运算符)。指针变量名:标识符。初值:可缺省。它可以是该类型的某一变量的地址。例如:int *ptr;float a=3.0, b, c4; float * pa=&a;float *p2=&a, &b;float *pn=NULL;float *pc=c;float *pf=new float;point *pp;其中:ptr是一个未赋初值的int型的指针变量。pa是float型的指针变量,被赋初值为&a,即pa当前的值为变量a的地址,或说pa指向变量
13、a。如把&a赋给ptr是不合法的,因为后者是整型指针。p 是浮点型指针数组,它由两个指针元素组成,分别被赋值&a,&b。 pn是一被赋初值为NULL的指针变量,规则规定NULL与整数0通用,它是唯一可以赋给任一类型指针变量的值,表示当前该指针未指向任一变量。因此,一个指针变量,可有三种状态:()未赋任何值,“悬空”状态。()被赋予NULL值。未指向任一变量。()指向某一变量。pc是一浮点型指针变量,由于c是浮点型数组的名,因此c又是指向数组的首元的指针,这时把c的值赋给pc,意味着pc的值为数组c 的首元c0的地址。pf也是浮点型指针变量,它的初值是通过动态内存分配运算
14、符new的“运算”结果,生成一无名的float型变量,其地址赋给了pf。new的使用将在本章介绍。由于这样产生的float型变量是无名的,因此在程序中对它的引用,主要是靠pf(用*pf表示)。pp是一个对象指针,因为point是一个已定义的类名,pp将可用来存放一个point类对象的地址,或说可用pp指向point类的一个对象(关于类和对象在第七章以后介绍)。指针变量的操作本节介绍与指针变量有关的运算。1取地址运算和取内容运算取地址运算为一单目运算,运算符为,例如:int a=3,*pa=&a;其中&a表示变量a的地址。它可以作为指针pa的值。使用&时应注意:()其后只
15、可用一变量名,而不可为一字面常量或一般表达式。()赋值时,pa与a的类型应一致。取内容运算为一单目运算,运算符为*,例如: int a=3,*pa=&a;*pa=5;cout<<a<<*pa;其中*pa5;和cout<<a<<*pa; 中的*pa表示指针pa当前所指向的变量a, 因此,*pa=5;相当于a=5; ,这里的*pa被称为“左值“,相当于变量a占用的空间,而后一个*pa则相当于变量a的值,故二者显示出的值应都是。运算*与&互为逆运算,这两个运算符都有不只一种含义,应注意不要混淆。2数组指针的算术运算如果指针变量是指向数组
16、的,例如:6.2 导出数据类型(2),指针(Pointer) 7int a20;int *pa=a;则指针pa可以有限制地进行运算或增量()减量()运算。 这时,可以用三种方式表示该数组的元素:(1)下标变量的形式:a0, a1, a2, a3, , a19;(2)用数组名a(一个常量指针):*a, *(a+1), *(a+2), *(a+3), ,*(a+19);(3)用指针变量pa(a):*pa,*(pa+1), *(pa+2), *(pa+3),,*(pa+19);虽然三种方式都可以,不过应注意的是,这里pa是变量,它可能是变化的,例如:pa+=3;执行后,pa已是指向a3,即*pa为a
17、3。pa-;执行后,pa已是指向a2。下面两个程序效果是一样的:#include <iostream.h>void main()int i,a5;cout<<"input 5 integers:"<<endl;for(i=0; i<5; i+)cin>>ai;cout<<"= Reverse output: ="<<endl;for(i=4; i>=0; i-)cout<<ai<<" "cout<<endl;#inc
18、lude <iostream.h>void main()int i,a5;cout<<"input 5 integers:"<<endl;for(i=0; i<5; i+)cin>>*(a+i);/*(a+i)全同于ai , a为数组首地址(一个常量指针) cout<<"= Reverse output: ="<<endl; for(i=4; i>=0; i-) cout<<*(a+i)<<" " /*(a+i)全同于aicou
19、t<<endl;当数据为多维数组时,上述对应关系为:int a23;int * pa=a; / 或*pa=a00;三种方式表示其六个元素:(1)a00,a01,a02,a10,a11,a12。(2)*a,*(a1),*(a2),*(a3),*(a4),*(a5)。(3)*pa,*(pa+1),*(pa+2),*(pa+3),*(pa+4),*(pa+5)。其中*(a4)即为a11,*(pa2)即为a02,应注意:(1)随时检查当前指针pa指向数组的哪个元素。例如pa=pa4;执行后,pa指向了a11。这时如果再做:pa;pa;就会出现指针pa“超界”,已不知它该指向谁了。(2)有时
20、可以把数组指针在限定范围(数组元素数)内,当作整数来运算,例如:int a45,n;int *pa=a,*pb&a34;n=pb-pa+1;coutnendl;输出的是数组的元素总数。C+的数组指针的+/-运算,使用起来比较方便,但很不安全,极容易出错, 必须予以注意。有的人把指针称为“数据结构中的goto语句”意思就是它的过于灵活容易造成程序出错,这也是一些新的语言,如JAVA,C#语言中取消指针类型的原因之一。3指针的关系运算指针变量可以参加关系运算。这要分三种情况:6.2 导出数据类型(2),指针(Pointer) 9(1)一般指针可以进行相等和不等的比较,指向同一变量(地址)者
21、为相等,否则不等。(2)任一指针可以和指针常量NULL进行相等和不等的比较。如一指针p已经指向了某变量,则它不等于NULL。(3)数组指针,可以指向该数组的各个元素,且一个数组的各个元素在内存中是顺序存放的,故数组指针之间不但可以进行相等和不等比较,也可以进行大于,小于,大于等于,小于等于等的比较。下面是有关的例子:float a,b,c10;float *pl=&a,*p2=NULL,*p3=C,*p4;if(pl != p2)p2=p32;if(p2p3)p2=1;顺便说明,指针和所有类型一样,它也可进行赋值运算。指针与数组指针与数组都是导出类型,它们都是在其它类型的基础上被定义的
22、。那么它们互相之间可否“导出”呢?1指向数组元素的指针前面被简单地称为数组指针的,实际上应更确切地称之为指向数组元素的指针,例如:int n10;int *pn=n;则指针 pn指向数组n的首元n0。在这里pn=n与pn=&n0;起相同的效果,因为数组名就是一个指向其首元的一个指针常量。2指向数组的指针把数组作为整体,称为指向数组的指针,对于这类指针,其说明语句格式为:类型名(*指针变量名)数组元素数;而指向多维数组的指针说明中,最后一项数组元素数可有多个。可以发现,指向多维(或一维)数组的指针说明与多维(或一维)数组说明只相差符号*和一对括号(*)。这个括号是很重要的,在下文介绍的指
23、针数组恰恰没有这对括号。例如:int (*pa)4;表示指针变量pa是一个指向一维整型数组的指针,该数组包含四个整型元素。一般指向数组的指针由多维数组的操作中被赋值:float A24;float(*pa)4;pa=A;这时指针pa指向一维数组A0,(A0有四个元素),执行增量运算pa+;后,pa指向一维数组A1,数组A1的四个元素是A10,A11,A12,A13。它们也可表示为(*pa)0,(*pa)1,(*pa)2,(*pa)3。从指向数组指针和指向数组元素指针的区别,可以看到:虽然指针变量的内容都是地址,但指针变量的类型(指向的对象类型)则决定了该地址指向的存储区的大小,例如:float
24、 *P=&A00;float(*pa)4;pa=A;虽然这时指针p和指针pa指向的地址是一样的,但P是指向一个整型下标变量A00,而pa则是指向整型一维数组A0,前者占内存空间可能是4bytes,而后者则占16bytes。3指针数组由指针组成的数组,常常在程序中出现,其说明格式为:类型名*数组名元素数n维指针数组为:类型名*数组名元素数元素数2元素数n; 从上面格式可知:(1)它比一般数组增加了符号*。(2)它比指向数组的指针,少了一对括号“()”。例如:int a,b,c,d,A24;int *p14=&a,&b,&c,&d;int *p22=A0,A
25、1;其中,指针数组pl由四个整型指针组成,把四个整型变量a,b,c,d的6.2 导出数据类型(2),指针(Pointer) 11地址赋给它们作初值是合法的。指针数组p2由两个整型指针组成,A0,A1是两个一维整型(含四个元素的)数组名,它们表示A00,A10的地址,作为p2的元素的初值也是合法的。从上面三个小节的内容可以看出下面定义的指针的区别:int *p;int *p12;int(*p2)4;p是指向int型变量的指针,p1是由两个整型指针组成的指针数组,而p2则是一个指向一维整型数组的指针。字符串指针字符串是一种特殊的数据形式,在数组一节,我们已经指出字符串和字符数组的关系。C+语言对于
26、字符串的操作提供了多种手段,其中利用字符串指针是最方便的一种。 说明与初始化字符串指针没有自己独立的形式,其说明语句的格式与字符类型指针相同,例如:char ch= 'a':char *pc1=&ch;char *pc2="world";char as10="Chinese";char *pc3=as;在上面的几个说明语句中:变量ch是字符型,它被赋初值字符a。变量pcl是字符指针,它被赋初值为字符变量的地址。这时pcl是一个字符型指针。变量pc2和pcl一样说明为字符指针,但它被赋初值为字符串常量“world”,于是pc2就成为
27、一个字符串指针。它的内容是字符串第一个字符w的存储地址。数组as 是一个长度为10的字符数组。为as所赋的初值为字符串常量“Chinese”,这个常量在数组中占八个分量的位置,七个字母和一个串尾符0。变量pc3说明为字符指针,并令其指向字符数组as的首元,这时,pc3也是一个字符串指针。字符串指针可以按一般字符指针的规则工作,例如:while(*pc2 != '0')cout*pc2+;执行上述while语句将在屏幕上显示world。类似地:while(*pc3 != '0')cout*pc3+;执行的结果是显示Chinese。字符串指针有时可以按不同于一般指针
28、变量的方式操作,即有时它可以表示字符串整体,而不是单单表示当前指向的那个字符。这一点为用户提供了方便,但也应在概念上搞清楚,以免混淆,请看下面介绍。 字符串的整体输入输出把字符串作为字符数组,然后按字符依次进行输入输出是可行的(如上述),但比较麻烦。因此,再提供整体输入输出的方法。把字符串变量用字符数组或字符串指针的形式表示,然后直接进行I/O操作:cin字符串;cout字符串;这里的字符串可以用字符串指针pc2,pc3或字符数组名as来表示,例如: char as 10="world";char *pc2"world";char *pc3=as;cou
29、tas;coutpc2;coutpc3;cout"world";后四个输出语句产生相同效果,都是输出了字符串world。char str 20;char *pc2=new char20;char *pc3=str;cinstr;cinpc2;cinpc3;6.2 导出数据类型(2),指针(Pointer) 13后三个输入语句允许输入长度不超过20的字符串,忽略前导空格,以空格作为串尾。 字符串指针数组以字符串指针组成的数组使用起来比较方便,例如:char *menu "File","Edit","Search",&
30、quot;Help";就是一个字符串指针数组,它的每个元素指向一个字符串常量。于是menu0,menu1,menu2,menu3将分别表示“File”,“Edit”,“Search”,“He1p”。4利用字符串指针的标准函数在头文件string.h中,C系统提供若干串处理函数的说明,它们大都利用字符串指针,下面列出几例:(1)求字符串长度。unsigned strlen(const char *str );返回字符串str的长度(不包括串尾符)。(2)字符串拷贝:char *strcpy(char *str1 ,char *str2);把字符串str2拷贝给字符串strl(覆盖原来内
31、容),返回strl的地址。(3)字符串连接:char *strcat(char *str1 ,char *str2);把字符串str2连接到字符串str1的后面(使str1加长),返回str1的地址。(4)字符串比较:int strcmp(char *str1 ,char *str2);此函数把ASCII码表作为字符表,按字典序比较两个字符串str1和str2。例如串“abc”小于串“abd”,串“xy”小于串“xyz”等等。根据两个串之间的大于,等于,小于关系,返回正整数,0和负整数。在C+程序中,有关指针、字符数组和字符串的操作是初学者较难掌握的,下面的程序实例可以帮助读者加深理解。#in
32、clude <iostream.h>void main()char s21, *ps=s;for (int i=0; i<20; i+)si='A'+i;s20='0' ps+; cout<<"ps="<<ps<<endl; ps+=2; cout<<"ps="<<ps<<endl;for (ps=&s19; ps>&s11; ps-=2)cout<<"*ps="<<*
33、ps<<endl;cout<<"ps="<<ps<<endl;运行结果:ps=BCDEFGHIJKLMNOPQRSTps=DEFGHIJKLMNOPQRST*ps=Tps=T*ps=Rps=RST*ps=Pps=PQRST*ps=Nps=NOPQRST指针与函数指针与函数的关系密切,主要分三部分,指针作函数参数,作函数返回类型和指向函数的指针。函数指针在Pascal语言是没有的。1指针作函数参数指针是一种特殊类型的数据,它的值是另外某种类型的变量的地址。因此,指针作函数的参数可以起到其它类型参数所起不到的作用。C语言中,函数的
34、参数(引用型参数除外)在调用过程中,须把实参(表达式)的值赋给仅在调用过程中有意义的形参,参加到函数体的运算之中。这样的机制很难实现对相对于函数的外部的“全局”变量作某些处理。例如要6.2 导出数据类型(2),指针(Pointer) 15编写一个交换两个浮点型变量内容(值)的函数:float a=1.0, b=2.1,c=3.2,d=4.5;为了交换变量a,b的值,当然可以直接用三条语句完成:float ta;a=b;b=t;就可达到目的。若要以函数形式表示,该函数应为无参函数:void swap(void)float t=a;a=b;bt;这个函数当然是对的。其中变量a,b是在函数外定义的全
35、局变量。它的明显缺点是没有“参数化”,没有通用性。当我们需要交换b和c,或交换c和d的值时,它就不能用,但是把它写成有参的形式:void swap(float x,float y)float tx;x=y;y=t;这个函数就是错的,当要把变量a,b内容交换时,函数调用:swap(a,b);不会把变量a和b的内容真的交换,它只是在函数执行时把临时的形参x和y的内容交换了,而这个x和y在函数执行完成就被释放掉。利用指针可以解决上面的问题,swap( )函数可以定义为:void swap(float *pa,float *pb)float t=*pa;*pa=*pb;*pb=t;;为了交换a和b,交
36、换c和d,只需调用二次:swap(&a,&b);swap(&c,&d);因为它通过参数传进了要改变内容的全局变量的地址,从而可以达到以参数形式输入,又能改变函数外变量内容的目的。2函数返回指针返回值为指针的函数称为指针型函数,其返回类型的说明应指明指针的对象类型后加“*”符号。例如:char *menu "Error!","File","Edit","Search","Help"char *menuitem(int m)return(m1 | m4)?menu0:
37、menum;这个函数menuitem()返回的是字符串指针,可直接调用函数menuitem( )来进行字符串的输入输出。指针型函数的设计,应注意返回的指针在该函数被调用的域内是有确切的对象变量的。切不可返回指向函数内说明的局部变量或参数变量的指针,或无指向的指针。3函数指针函数不是数据,但它与变量还是有两点相通之处:一个是它有类型(返回类型),另一个是它也有地址,称为人口地址,故在有的书中也勉强地把函数仍归为一种特殊的数据“类型”。函数的地址也可作指针的值,这就是函数指针。函数指针的说明格式与函数的原型相似,主要区别是:原来的函数名,用 *函数指针名所代替,例如:int(*pf)(float)
38、;其中pf是一个函数指针变量,由于对pf的说明中已规定了函数的返回类型(有时还包括存储类型)和参数表,因此,指针pf只能够指向这类函数。例如:int f1(float);int f2(char);int f3(float);int f4(float);设f1,f2,f3,f4是4个已说明的函数,这时,下面的说明和赋值,就有合法与不合法的区别:int(*pf)(float)=&f1; /合法int(*pf1)(char)=&f1; /不合法pf=&f4; /合法pf=&f2; /不合法6.2 导出数据类型(2),指针(Pointer) 17pf=&f3;
39、/合法C语言本身不允许把函数作为参数,然而有了函数指针,就可以通过函数指针,起到把函数作为参数的作用。 例如:用来计算函数定积分的函数simpson(),对于不同的函数计算其定积分值,应该有一个函数参数,在C程序中用函数指针可以方便地解决这个问题:float simpson(float a,float b,float(*pf)(float);参数a,b给出定积分的上下限,函数指针pf则指向被积函数(其函数体从略)。在使用时可以对不同的浮点函数和上下限,调用simpson()计算其定积分:float a=3.2,b=4.2;float f1(float); /函数体从略float f2(floa
40、t); /函数体从略float(*pfl)(float)=&f1: /函数指针pf1指向函数f1 coutsimpson(a,b,pfl)endl ;a4.0;b=10.5;pfl=&f2; /pf1指向函数f2coutsimpson(a,b,pfl)endl;两次调用分别计算两个不同函数fl和f2的定积分值,这样的功能没有函数指针是难以实现的。函数指针的使用属于较深入的话题,这里就不进一步展开了。指针与动态内存分配动态分配运算符在第四章,我们已经介绍了动态分配运算符new和delete。new和delete的使用,也是C+语言优于C语言的特征之一。New运算是程序中除了变量说
41、明之外,又一种生成变量的方法,不过用new生成的变量为无名动态变量,它返回的是一个该类型的指针值,程序通过指针对这个变量进行操作。例如:int *pi,a=5;char *pc;float *pf,f=3.0;pi=new int; /生成一动态int类型变量pc=new char4; /生成动态char类型数组pf=new float(4.7); /生成动态float类型变量且赋初值 *pia*a; /动态变量*pi被赋值for(int i=0;i4;i) /动态char型数组的每个分量被赋值 *(pci)a;f+=*pf; /动态变量*pf参加运算我们可以把用new生成的一个动态变量与用变
42、量说明语句说明的一个变量作比较:·都要指出变量的类型,类型名要放在new之后。·都可以赋初值,不是用初值的方式而是用括号(初值)的方式。·都可以说明为数组,加数组运算符。·动态变量没有变量名,须用指针变量接收到它的地址后,通过指针运算符进行操作。Delete运算用来撤消或释放由ne生成的动态变量,例如:delete pa; /释放pa指向的动态int变量delete pf; /释放pf指向的动态float变量delete pc; /释放pc指向的动态数组动态变量与一般变量的主要区别就是它可以在程序运行过程中任意被撤销。而一般变量则必须在其所说明的程序块结
43、束时自动撤销。用指针进行内存动态分配C程序中对变量、数组等的说明实际上就是为它们进行内存分配,所分配的空间及其内容,通过变量名引用。用这种方式为变量分配空间,其占用形式比较死板。有了运算符和,就可以实现一种动态分配内存的形式,即通过指针引用,而内存的分配和释放可以在程序的任何地方进行。语言中没有运算符和,其动态内存分配依靠若干库函数完成,比较复杂,这也是语言优于语言的特点之一。例如:int *pint;char *pchar;float *pfloat;pfloat = new float;指针与动态内存分配19pchar = new char;pint = new int;这样就生成了三个(
44、浮点型、字符型、整型)变量,但它们没有名字。由于三个变量的地址分别存在指针pfloat,pchar和pint,故在程序中使用这三个变量时,全通过指针:*pchar = A;*pint = 5;*pfloat = 4.7;*pint+;当不再需要这些变量时,可在程序的任何地点释放掉它们: delete pchar;delete pint;delete pfloat;注意,这里释放的是动态的(,)变量,而不是指针变量(pchar, pint, pfloat)。这种动态生成的变量,在使用上方便灵活,其必要条件就是应用相应的指针来操纵它。读者在使用动态变量时应注意的是,要保护动态变量的地址。例如在执行
45、pi=new int;之后,不要轻易地冲掉指针pi中的值,假如执行了pi=&a;语句之后,再释放原来生成的动态变量:delete pi;已经达不到原来的目标了。 C中new运算类似于Pascal语言中new过程的使用,不过它不作为相应的函数处理。C还保留了从C语言中继承下来用于动态存储分配的malloc(),free( )等标准函数,它们已经可以为new和delete运算所取代。导出数据类型(),引用()引用(reference)是C语言特有的(C和Pascal语言不具备)数据形式。它的存在不仅像数组和指针那样依赖于已有的类型,而且它还依赖于一个已有的变量。从直观上说,一个引用变量是一
46、个已定义的变量的别名。这种引用型变量在作为函数的参数和返回类型时,其使用方式与指针类型有相似性。上文已经提到指针类型的缺点,因此建议读者在学习和掌握C语言过程中,应体会引用类型的重要性,理解它的原理和特征,掌握它的使用方法,在既可以使用指针类型又可以使用引用类型时,多用引用类型。由于一些新的语言,如,等,取消了指针类型而仅保留引用类型,引用类型的重要性就更容易理解了。引用变量的说明引用变量的说明格式与指针变量说明相似:类型名变量名=对象变量名;与指针说明的区别是:()用符号代替符号*。()赋初值部分不可缺省。例如: int size=5,color;int refs=size;int refc
47、=color;引用变量refs,refc相当于整型变量size和co1or的别名,即:refc3;其效果为变量color和refc同时被赋值为3。refs+=2;其效果是变量size和refs同时在原来值5的基础上加2,即改变为7。 引用和指针的比较C语言中增加引用这种数据形式,主要是用于在一定的范围内,代替或改进指针的作用。虽然在说明方式上十分相似,但在概念上却有着明显的不同。其区别最主要有两点:()指针表示的是一个对象变量的地址,而引用则表示一个对象变量的别名。因此在程序中表示其对象变量时,前者要通过取内容运算符*,而后者可直接代表: int m,n;int *p = m;int r =
48、m;而在对m赋值时,下面三者是等价的:m = 5;*p = 5;6.4 导出数据类型(3), 引用(Reference) 21r = 5;引用类型变量与其他类型变量不同,它没有自己的值和地址空间,只是作为另一变量的别名,在它的生存期期间两个名字绑定在一起,因此,引用类型的使用是有限制的:引用类型变量不能被引用;引用类型不能组成数组;引用类型不能定义指针。正是这些限制,保证了它的安全性,反而成为人们选择它取代方便灵活的指针的原因。()指针是可变的,它可以指向变量m,也可以指向变量n,而引用变量只能在定义时一次确定,不可改变。 int m,n;int * p = m;int r = m:以后执行
49、p = n;是合法的,而引用变量r只可与m相联。因此,有人说可以把引用看成指针常量,即:const int * p = m;int r = m;二者更相近。不过这里p对应的是m的地址,而引用变量r不关心m的地址,它直接与变量m本身相关。引用型参数把函数的参数说明为某一类型(或类)的引用类型,意味着这个参数为“变量参数”,称为引用调用。引用型参数在函数被调用时,相应的实参必须是对应类型的变量或对象;在调用函数体运行前,生成该实参的引用变量;在整个函数体运行过程中,这个引用变量相当于作为实参的变量或对象的别名,直到函数调用结束返回。引用型参数的优点是:()它可以把函数外的变量以别名的形式引入到函数
50、体内参加运算,非常方便,这种方式比用指针解决这个问题更合理。()它不必在调用时创建与实参变量或对象对应的值参数变量,当实参变量或对象占用内存较多时,这可以节省内存。()用指针也可以实现类似于引用调用的效果,但由于指针可以改变内容,任意赋值,因此它不如引用型参数安全。关于引用调用,在后面的章节有更多的实例介绍。引用型的函数返回值一般的函数要返回一个值,例如: int max(int a,int b)return(ab)?a : b;;这个函数返回二者之中较大的值,可令:int cmax(3,5);当把函数的返回类型说明为引用型时,这个函数返回的不仅仅是某一变量或对象的值,而且返回了它的“别名”,
51、该函数的调用也可以被赋值。让我们举例说明:int a = 2,b = 3,c = 4;int * p a;int r = b;下面的一些表达式:c,ab,*p,rc*b,r其中ab,rc*b是表达式,它们仅可计算出一个值。另外c,*p,r也是表达式,而且它们又可被赋值:c=5,*p=6,r=7,等等,因此这类表达式被称为“左值表达式”。引用型返回类型的函数调用就是一种左值表达式,可以作为值,也可被赋值: int a=3,b=5,c;int maxr(int & m,int & n)if(m>n)return m;return n;函数maxr( )可以有两个用法: c =
52、 maxr(a,b);它把变量a,b中较大者的值赋给了变量c,返回的是较大者的值。 maxr(a,b)=10;它把变量a,b中较大者的值改变为10,返回的是较大者本身。maxr(a,b)+;它把变量a,b中当前较大者的值加1,返回的也是较大者本身。函数的调用本身也可以作为变量和对象来使用,这是引用概念在C程序设计中非常重要的应用,它所提供的编程灵活性,在运算符的重载,在C6.5 程序实例 23语言提供的I/O系统中有十分重要的体现。在有些场合下,以引用代替指针,除了可以实现相同的目标外,同时增加程序的安全性,引用型函数可以作为“左值”,它的这种功能可以说是程序设计语言的一个重要发展,C程序员在
53、程序设计中应充分使用引用概念,必然有利于提高程序的水平。程序实例按人名字典序排列电话簿本节的程序涉及应用编程经常碰到的字符串和文本的处理,已知有n个人的姓名,以及每个人有一个电话号码,然后按这些人名的字典序排列且输出其电话号码表。/program6_2.cpp# include <iostream.h># include <iomanip.h>void swap (char* & ,char* & );int compword (char*,char*);void main(void)const int n=5,t=8;int i,j,index;cha
54、r *telen,*sele;char *namen="Zhaolin","Mazhigang","Liguoping","Sunyingmin","Mazilan"for (i=0; i<n; i+)cout<<"Input"<<namei<<"'s telephone number:" ;telei=new(chart);cin>>telei;cout<<endl;cout<<setw(15)<<"NAME"<<setw(15)<<"TELE NO" ;for (i=0;i<n-1;i+)sele=namei;index=i; for (j=i+1;j<n;j+) if (compword(namej,sele) sele=namej; index=j;swap (nameindex, namei);swap(teleindex, telei);for(i=0;i<n;i+)cout<<endl<<" "<
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 管材管件购销合同
- 建设工程勘察合同
- 2025年广州货运从业资格证考试的技巧
- 小学二年级下册数学口算题
- 电力技术支持合同(2篇)
- 2024-2025学年高中生物课时分层作业11生命活动的能量“通货”-ATP含解析苏教版必修1
- 2024-2025学年高中语文第4单元寻觅文言津梁研习.活动单元序列写作4论证方法多样化-议论文成功的关键学案含解析苏教版必修3
- 2024-2025学年四年级数学上册第八单元垂线与平行线课时8认识平行线教案苏教版
- 2024年高中物理第五章曲线运动第一节曲线运动训练含解析新人教版必修2
- 高中文科班班主任学期工作计划
- 擘画未来技术蓝图
- 基于情报基本理论的公安情报
- 《“白山黑水”-东北三省》示范课课件(第1课时)
- 孔氏家庙的社会调查报告
- 员工节能环保培训课件
- 四年级下册部编版语文教学参考教师用书
- 华为公司的内部审计制度
- 月球基地建设与运行管理模式
- 肿瘤医院病历书写培训课件
- 《蓄电池培训》课件
- 32软件测试报告GJB438C模板
评论
0/150
提交评论