课件第7章指针和字符串_第1页
课件第7章指针和字符串_第2页
课件第7章指针和字符串_第3页
课件第7章指针和字符串_第4页
课件第7章指针和字符串_第5页
已阅读5页,还剩97页未读 继续免费阅读

下载本文档

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

文档简介

2023/5/2211C++程序设计主讲中南大学软件学院谭长庚

2010.102023/5/222Chapter7指针与字符串PointersandC-Strings2023/5/223ObjectivesWhatapointeris?(§7.1).Declareapointerandassignavaluetoit(§7.2).Toaccesselementsviapointers(§7.2).Topassargumentsbyreferencewithpointers(§7.3).Therelationshipbetweenarraysandpointers(§7.4).Toaccessarrayelementsusingpointers(§7.5).Todeclareconstantpointersandconstantdata(§7.5).Howtoreturnpointersfromfunctions(§7.6).Toallocatememorydynamicallyusingthenewoperator(§7.7).Tousingthecharacterfunctions(§7.9.1).Tostoreandaccessstringsusingarraysandpointers(§7.9.2).Toreadstringsfromthekeyboard(§7.9.3).Toprocessstringsusingthestringfunctions(§7.9.4).2023/5/2247.1指针的概念1.内存与变量地址

内存地址:内存是计算机用于存储数据的存储器,以一个字节作为存储单元,为了便于访问,给每个字节单元一个唯一的编号,第一字节单元编号为0,以后各单元按顺序连续编号,这些单元编号称为内存单元的地址。

变量地址:变量所分配存储空间的首字节单元地址(字节单元编号)。

2023/5/225

每个变量都通过变量名与相应的存储单元相连系,具体分配哪些单元给变量,由C编译系统完成变量名到对应内存单元地址的变换。

变量分配存储空间的大小由类型决定。变量的值则是指相应存储单元的内容。地址运算符:&

例:intvar;则&var表示变量var在内存中的起始地址3.内存存取方式直接存取:直接按变量名或地址存取变量值的方式间接存取:通过定义一种特殊的变量专门存放内存或变量的地址,然后根据该地址值再去访问相应的存储单元。2.变量的三要素:名字(地址)、类型与值2023/5/226

系统为特殊变量p(用来存放地址的)分配的存储空间地址是4800,p中保存的是变量a的地址,即4000,当要读取a变量的值12345时,不是直接通过a变量,也不是直接通过保存12345的内存单元的地址4000去取值,而是先通过变量p得到p的值4000,即a的地址,再根据地址4000读取它所指向单元的值12345。

这种间接的通过变量p得到变量a的地址,再存取变量a的值的方式即为“间接存取”。

通常称变量p指向变量a,变量a是变量p所指向的对象…400012345400040024800pap(4800)

p(4800)

a(4000)

4000123454000间接存取示意图2023/5/2274.指针的概念

在C++语言中,用指针来表示一个变量指向另一个变量这样的指向关系。所谓指针即地址。一个变量的指针即该变量的地址,如4000就是指向变量a的指针。

指针变量:专门存放地址的变量,如p即是一个指针变量,它存放的是a的地址4000。

以后把指针变量简称为指针。2023/5/228

1.指针变量的定义

类型标识符*指针变量名;例:float*p1;(定义p1为指向实型变量的指针变量)char*p2;(定义p2为指向字符型变量的指针变量)在指针变量定义中,*(asterisk)是一个说明符,它表明其后的变量是指针变量,如p1是指针变量,而不要认为“*p1”是指针变量。指针变量定义时指定的数据类型不是指针变量本身(变量存放的值)的数据类型,而是指针变量所指向的对象(或称目标)的数据类型指针变量存放的是所指向的某个变量的地址值,而普通变量保存的是该变量本身的值指针变量并不固定指向一个变量,可指向同类型的不同变量7.2指针变量的定义(DeclareaPointer)2023/5/2292.指针运算符与地址运算符与指针引用有关的两个运算符:&与*。

&:取地址运算符

*:指针运算符,或称指向运算符、间接访问运算符。指针指向的对象的表示形式:*指针变量此处*是访问指针所指对象的运算符,与指针定义时的*不同。inta,b;doublex;int*p;//定义整型指针,p只能指向整型变量p=&a;//p指向a;*p即变量a;cout<<*p<<a;输出相同值p=&b;//p亦可指向b;*p即变量b;cout<<*p;输出b的值p=&x;//wrongp只能指向整型变量2023/5/22103指针的引用-间接引用(Dereferencing)

①*指针变量名——代表所指变量的值。②指针变量名——代表所指变量的地址。有定义:inta,*p=&a;*p表示p指向的对象a,*p与a是等价的,可象普通变量一样使用。例如:a=12;a++;//直接引用(directreference)

*p=12;(*p)++;//间接引用(indirectreference)

cin>>*p;//scanf(“%d”,p);p内容是地址,故不加&//scanf(“%d”,&a);cout<<*p<<a;注意:*与&具有相同的优先级,结合方向从右到左。这样,&*p即&(*p),是对变量*p取地址,它与&a等价p与&(*p)等价,a与*(&a)等价。

2023/5/22117.3指针变量初始化(InitializingPointer)

若有定义:

inta,*p;语句仅仅定义了指针变量p,但指针变量并未指向确定的变量(或内存单元)。因为这些指针变量还没有赋给确定的地址值(有任意值)。只有将某一具体变量的地址赋给指针变量之后,指针变量才指向确定的变量(内存单元)。使用一个未初始化的指针会导致严重问题*p=50;p未初始化,不知指向哪里,给其指向对象赋值会导致不可预知的后果;p=&a;*p=50;相当于给a赋值2023/5/2212指针变量初始化:在定义指针变量时给指针一个初始值语法形式数据类型*指针名=与指针类型相同的初始地址例:inta;

int*pa=&a;40003a(4000)pa*pa注意事项用变量地址作为初值时,该变量必须在指针初始化之前已说明过,且变量类型应与指针类型一致。可以用一个已赋初值的指针去初始化另一个指针变量。不要用一个内部auto变量去初始化static指针。int*pa=0;//说明pa不指向任何对象。但不能用其它常整数初始化:int*pa=4000;×intarea=1;double*pArea=&area;//Wrong2023/5/2213例7.1void类型指针的使用voidvobject;//错,不能声明void类型的变量void*pv; //对,可以声明void类型的指针

//可指向任何变量int*pint;inti;voidmain()//void类型的函数没有返回值{ pv=&i; //void类型指针指向整型变量

//void指针赋值给int指针需要类型强制转换:pint=(int*)pv;}2023/5/2214例7.2指针测试#include<iostream>usingnamespacestd;intmain(){intcount=5;int*pCount=&count;cout<<"Theaddressofcountis"<<&count<<endl;cout<<"Theaddressofcountis"<<pCount<<endl;cout<<"Theaddressofpcountis"<<&pCount<<endl;cout<<"Thevalueofcountis"<<count<<endl;cout<<"Thevalueofcountis"<<*pCount<<endl;return0;}都为变量count的地址指针变量pcount的值即:变量count的地址变量count的值指针变量pcount的地址2023/5/2215指针变量的算术运算指针与整数的加减运算指针p加上或减去n,其意义是指针当前指向位置的前方或后方第n个数据的地址。这种运算的结果值取决于指针指向的数据类型。指针加一,减一运算指向下一个或前一个数据。例如:y=*px++相当于y=*(px++)

(*和++优先级相同,自右向左运算)3指针运算(概述)2023/5/2216papa-2pa-1pa+1pa+2pa+3*(pa-2)*pa*(pa+1)*(pa+2)*(pa+3)*(pa-1)short*pa162023/5/2217关系运算指向相同类型数据的指针之间可以进行各种关系运算。指向不同数据类型的指针,以及指针与一般整数变量之间的关系运算是无意义的。指针可以和零之间进行等于或不等于的关系运算。例如:p==0或p!=0赋值运算向指针变量赋的值必须是地址常量或变量,不能是普通整数。但可以赋值为整数0,表示空指针。指针变量的关系运算2023/5/2218指针运算(详述)-赋值(1)直接给指针变量赋值指针名=地址;inta,*p;p=&a;“地址”中存放的数据类型与指针类型必须相符。向指针变量赋的值必须是地址常量或变量,不能是普通整数。但可以赋值为整数0,表示空指针。指针的类型是它所指向变量的类型,而不是指针本身数据值的类型,任何一个指针本身的数据值都是unsignedlongint。允许声明指向void类型的指针。该指针可以被赋予任何类型对象的地址。例:void*general;

general=p;2023/5/2219例如:inta,b;int*pa,*pb;doublex,*px;pa=&a;pb=&b;px=&x;paapbb2023/5/2220(2)相同类型的指针变量间的赋值pa与pb都是整型指针变量,它们间可以相互赋值,如:pb=pa;即pa,pb都指向变量a,此时a、*pa、*pb是等价的。指针指向变化如下图:注意:只有相同类型的指针变量才能相互赋值,px=pa;是不允许的。因为pa是整型指针,px是浮点型指针。&a&bpapba,*pab,*pb&a&apapba,*pa,*pbb2023/5/2221(3)给指针变量赋空值

给指针变量赋空值,说明该指针不指向任何变量。

“空”指针值用NULL表示,NULL是在头文件stdio.h中预定义的常量,其值为0,在使用时应加上预定义行,如:

#include"stdio.h"int*pa=NULL;

亦可以用下面的语句给指针赋“空值”:a=0;

或:pa=’\0’;

这里指针pa并非指向0地址单元,而是具有一个确定的“空值”,表示pa不指向任何变量。注意:指针虽然可以赋值0,但却不能把其它的常量地址赋给指针。例如:pa=4000;是非法的。2023/5/2222例7.3从键盘上输入两个整数到a、b,按由大到小输出#include<stdio.h>voidmain(){inta,b,*pa=&a,*pb=&b,*pscanf(″%d%d″,&a,&b);if(*pa<*pb){p=pa;pa=pb;pb=p;}

printf(″\na=%d,b=%d\n″,a,b);printf(″\nmax=%d,min=%d″,*pa,*pb);//pa指向大数,pb指向小数}2023/5/2223若输入:1222↙

输出结果:a=12,b=22

max=22,min=12(a)(b)(c)指针变化示意图1222ppapb1222ppapbpapbab2023/5/2224

指针的算术运算(1)加减运算:

一个指针可以加、减一个整数n,其结果与指针所指对象的数据类型有关。指针变量的值应增加或减少“n×sizeof(指针类型)”。

加减运算常用于数组的处理。对指向一般数据的指针,加减运算无实际意义。例如:

inta[10],*p=a,*x;

x=p+3;/*实际上是p加上3*4个字节赋给x,x指向数组的第三个分量*/

对于不同基类型的指针,指针变量“加上”或“减去”一个整数n所移动的字节数是不同的。例如:

floata[10],*p=a,*x;

p=p+3;/*实际上是p加上3*4个字节赋给x,x依然指向数组的第三个分量*/2023/5/2225(2)自增自减运算指针变量自增、自减运算具有上述运算的特点,但有前置后置、先用后用的考虑,务请小心。例如:

inta[10],*p=a,*x;

x=p++;//x第一个元素分量,p指向第二个元素

x=++p;//x、p均指向数组的第二个分量*

p++相当于*(p++)。*(p++)与(*p)++含义不同,前者表示地址自增,后者表示当前所指向的数据自增。2023/5/22262.*&a的含意是什么?(答:a)3.(*p)++相当于什么?(答:a++)思考:1.若有定义inta,*p;执行了“p=&a”,则:“&*p”的含意是什么?(答:相当于&a)2023/5/2227

指针的关系运算

与基本类型变量一样,指针可以进行关系运算。在关系表达式中允许对两个指针进行所有的关系运算。若p,q是两个同类型的指针变量,则:

p>q,p<q,p==q,p!=q,p>=q都是允许的。指针的关系运算在指向数组的指针中广泛的运用,假设p、q是指向同一数组的两个指针,执行p>q的运算,其含义为,若表达式结果为真(非0值),则说明p所指元素在q所指元素之后。或者说q所指元素离数组第一个元素更近些。注意:在指针进行关系运算之前,指针必须指向确定的变量或存储区域;另外,只有相同类型的指针才能进行比较。2023/5/2228补充:多级指针多级指针:把指向指针型数据的指针变量称为多级指针(指向指针的指针)二级指针的定义形式如下:

数据类型**指针变量例如:

inta,*p,**pp;a=22;p=&a;pp=&p;假设变量a的地址为4000,指针p的地址为4100,二级指针pp的地址为4800。a、p、pp三者的关系如上图。&p=4100&a=400022pp(4800)p(4100)a(4000)cout<<**p<<a;2023/5/22297.3用指针实现实参的引用传递

PassingArgumentsbyReferencewithPointersTherearethreewaystopassargumentstoafunctioninC++:passbyvalue

passbyreferencewithreferencearguments

passbyreferencewithpointers

2023/5/2230例7.4测试指针参数#include<iostream>usingnamespacestd;//Swaptwovariablesvoidswap(int*pValue1,int*pValue2){//Swapn1withn2inttemp=*pValue1;*pValue1=*pValue2;*pValue2=temp;}intmain(){intnum1=1,num2=2;cout<<"Beforeinvokingtheswapfunction,num1is"<<num1<<"andnum2is"<<num2<<endl;swap(&num1,&num2);cout<<"Afterinvokingtheswapfunction,num1is"<<num1<<"andnum2is"<<num2<<endl;return0;}2023/5/22317.4数组与指针(ArraysandPointers)Recallthatanarrayvariablewithoutabracketandasubscriptactuallyrepresentsthestartingaddressofthearray.Inthissense,anarrayvariableisessentiallyapointer.Supposeyoudeclareanarrayofintvalueasfollows:intlist[6]={11,12,13,14,15,16},*p;数组名是一个常量指针,它的值为该数组的首地址p=list;p=&list[0]等价2023/5/22321.指向数组元素的指针声明与赋值例:inta[10],*pa;pa=&a[0];或pa=a;通过指针引用数组元素经过上述声明及赋值后:*pa就是a[0],*(pa+1)就是a[1],...,*(pa+i)就是a[i].a[i],*(pa+i),*(a+i),pa[i]都是等效的。不能写a++,因为a是数组首地址是常量。2023/5/2233指向数组的指针变量p:inta[10],*p=a;&a[0]13151719pa[0]:a[9]p[9]a+0p+1

或a+1p+9

或a+9*(a+9)或*(p+9)2023/5/2234C++规定:p+1指向数组的下一元素(而不是将p值简单地加1)。p+1意味着使p的原值(地址)加d个字节(d为一个数组元素所占的字节数)。如果p的初值为&a[0],则:(1)p+i和a+i就是a[i]的地址,或者说它们指向a数组的第i个元素(见下页图)。(2)*(p+i)或*(a+i)是p+i或a+i所指向的数组元素,即a[i]。(3)指向数组的指针变量也可以带下标,如p[i]与*(p+i)、a[i]等价。2023/5/2235*(p+i)a数组a[0]a[1]a[2]a[i]a[9]pp+1,a+1p+i,a+ip+9,a+9综上所述,引用一个数组元素有二法:(1)下标法:如a[i]形式;(2)指针法:如*(a+i)或*(p+i)。其中a是数组名,p是指向数组的指针变量,其初值p=a。2023/5/2236voidmain(){inta[10];inti;for(i=0;i<10;i++)scanf("%d",&a[i]);printf("\n");for(i=0;i<10;i++)printf("%d",a[i]);}例7.5用三种方法输出数组全部元素。(1)下标法main(){inta[10];inti;for(i=0;i<10;i++)scanf("%d",&a[i]);printf("\n");for(i=0;i<10;i++)printf("%d",*(a+i));}指针法12023/5/2237(3)用指针变量指向数组元素main(){inta[10];int*p,i;for(i=0;i<10;i++)scanf("%d",&a[i]);printf("\n");for(p=a;p<(a+10);p++)printf("%d",*p);}三种方法的比较:用下标法比较直观,能直接知道是第几个元素;而用指针法则执行效率更高。2023/5/2238使用指针变量时,应注意:(1)指针变量可实现使本身的值改变。

P++合法;但a++不合法(a是数组名,代表数组首地址,在程序运行中是固定不变的。)(2)要注意指针变量的当前值。main(){inta[10];int*p,i;p=a;for(;p<a+10;p++)scanf("%d",p);printf("\n");for(;p<(a+10);p++)printf("%d",*p);}不能&p增加:p=a;2023/5/2239(3)*p++相当于*(p++),因为*与++优先级相同,且结合方向从右向左,其作用是先获得p指向变量的值,然后执行p=p+1;(4)*(p++)与*(++p)意义不同,后者是先p=p+1,再获得p指向的变量值。若p=a,则输出*(p++)是先输出a[0],再让p指向a[1];输出*(++p)是先使p指向a[1],再输出p所指的a[1]。(5)(*p)++表示的是将p指向的变量值+12023/5/22402.指向由m个元素组成的一维数组的指针变量定义形式:类型(*指针变量)[元素个数]如:int(*p)[4];2023/5/2241注意:(1)int(*p)[4];定义一个指针变量p,p指向包含4个元素的一维数组。(2)p+i与*(p+i)的区别:

p+i是指向第i行的指针(第i行的首地址);*(p+i)是指向第i行第1个元素的地址;

两者数值相等,但含义不同:p+i的增值将以行长为单位,而*(p+i)增值将以元素长度为单位。

2023/5/2242指针数组:数组的元素是指针型,是指针变量的集合。即它的每一个元素都是指针变量,且都具有相同的存储类别和指向相同的数据类型。指针数组的定义形式为:

类型标识符*数组名[数组长度说明];例如:

int*p[10];由于[]比*的优先级高,因此p先与[10]结合成p[10],而p[10]正是数组的定义形式,共有10个元素。最后p[10]与*结合,表示它的各元素可以指向一个整型变量。3.指针数组2023/5/2243指针数组广泛应用于对字符串的处理例如有定义:

char*p[3];定义了一个具有三个元素p[0],p[1],p[2]的指针数组。每个元素都可以指向一个字符数组,或字符串。若利用数组初始化,则:char*p[3]={“Basic”,“c++”,“pascal”};P[0]指向字符串“Basic”;P[0]指向字符串“c++”;P[0]指向字符串“pascal”

;2023/5/2244例7.6字符指针数组的赋值

…#defineNULL0voidmain(){staticchara[]=“Fortran”;staticcharb[]=“COBOL”;staticcharc[]=“Pascal”;inti;char*p[4];p[0]=a;p[1]=b;p[2]=c;p[3]=NULL;for(i=0;p[i]!=NULL;i++)cout<<“Language”<<i+1<<“is”<<p[i]<<‘\n’;}2023/5/22457.5常量指针C语言中,用define宏定义来定义常量。但在编译预处理时将符号常量用其后的常量作简单的替换,易出现意想不到的问题。例如:

#defineN2 #defineMN+1 #defineNUM(M+1)*M/2

通常将NUM的值看成6:NUM=(3+1)*3/2=6

实际上编译预处理后其值:NUM=(2+1+1)*2+1/2=8C++常量定义格式为:const类型标识符常量标识符=常量表达式;const解决了上述问题,它定义的常量可以用指针操作。

2023/5/2246const用于修饰指针时,有三种组合:(1)指向常量的指针,定义格式为:

const类型标识符*变量名=常量;例如:

constchar*str=”China”;或charconst*str=”China”;str是一个指向常量的指针,称为常量指针,不能改变所指常量的值。例如:str[0]=’S’;//wrong重新赋值不允许但指针str本身不是一个常量,而是一个变量,可以指向另一个常量。例如:str=”Changsha”;2023/5/2247不能通过指针来改变所指对象的值,但指针本身可以改变,可以指向另外的对象。例:constchar*name1="John";//指向常量的指针chars[]="abc";name1=s;//正确,name1本身的值可以改变*name1='1';//编译时指出错误2023/5/2248(2)指针类型为常量,称为指针常量,定义格式为: 类型标识符*const指针变量名=常量;例如:

char*conststr=”China”;不能写为:charconst*str=”China”;str是一个常量,不能修改str的值。例:str=”Changsha”;//wrong在C++中是非法的。但str没有定义为指向常量,其所指的值可以改变。例如:str[0]=’S’;//ok,是合法的。2023/5/2249(3)指向常量的常指针,指针和它所指的对象都为常量

const类型标识符*const变量名=常量;例如:constchar*conststr=”China”;指针str不能指向”China”以外的字符串,也不能改变指针所指的对象.例如:下面的操作都是错误的。

str=”Changsha”;

str[2]=’A’;

doubleradius=5;double*constpValue=&radius;2023/5/2250例7.7#include<iostream>usingnamespacestd;voidprintArray(intconst*,constint);//prototypeintmain(){intlist[6]={11,12,13,14,15,16};printArray(list,6);return0;}voidprintArray(intconst*list,constintsize){for(inti=0;i<size;i++)cout<<list[i]<<"";}2023/5/22517.7动态内存分配-new和delete算符

C++可以动态的分配和撤销内存空间。new分配存储单元,格式为:

new数据类型或new数据类型[元素个数];//对数组例如:(1)int*p;p=newint;//分配一个整型单元,返回地址指针赋给p(2)float*pf=newfloat; //分配一个浮点4字节用于浮点数,返回地址指针赋给pf。(3)申请一块80个字符的空间: char*PAarrayNew=newchar[80];2023/5/2252delete释放用new分配的空间,格式为:

delete指向分配空间的指针变量;

//分配的是单个对象空间或:delete[]指向分配空间的指针变量;

//分配的是数组空间例如:释放例(1)的内存:

deletep;释放例(3)的空间:

delete[]PArrayNew;

2023/5/2253注意:使用new分配存储单元,必须指明存放数据的数据类型,据此自动确定分配所需内存,返回其首地址。若无法分配到所要的内存,则返回0。用new分配的存储单元,必须用delete释放。用new分配的存储块不能自动初始化为0。但可以在分配时用表达式或表达式序列显式初始化存储单元;new不能自动对数组进行初始化。例如:int*P_Int=newint(0);//new申请1个整型变量,初始化为0int*PArray=newint[10](0);//错误:不允许初始化数组2023/5/22547.6指针与函数1.指针作为函数参数利用指针作函数参数,可以实现函数之间多个数据的传递,当形参为指针变量时,其对应实参可以是指针变量或存储单元地址。函数形参为指针变量,用指针变量或变量地址作实参例7.8编写一个交换两个变量的函数,在主程序中调用,实现两个变量值的交换。2023/5/2255程序如下:#include<stdio.h>voidmain(){inta,b;int*pa,*pb;voidswap(int*p1,int*p2);/*函数声明*/scanf(″%d%d″,&a,&b);pa=&a;/*pa指向变量a*/pb=&b;/*pb指向变量b*/swap(pa,pb);printf(″\na=%d,b=%d\n″,a,b);}或:swap(&a,&b);voidswap(int*p1,int*p2){inttemp;temp=*p1;*p1=*p2;*p2=temp;

}2023/5/2256两点说明:(1)若在函数体中交换指针变量的值,实参a、b的值并不改变,指针参数亦是传值。例如:

int*p;

p=p1;p1=p2;p2=p;不要希望如此完成处理。

(2)函数中交换值时不能使用无初值的指针变量作临时变量。例如:

int*p;*p=*p1;*p1=*p2;*p2=*p;

p无确定值,对p的使用可能带来不可预期的后果。2023/5/22572.指针函数

(ReturningPointersfromFunctions)指针函数:是指返回值为指针的函数指针函数的定义形式:

类型标示符*函数名(参数)例如:int*fun(inta,intb){函数体语句}在函数体中有返回指针或地址的语句,形如:return(&变量名);或return(指针变量);并且返回值的类型要与函数类型一致。

2023/5/2258#include<iostream>例7.9指针函数usingnamespacestd;int*reverse(intconst*list,constintsize){intresult[6];

for(inti=0,j=size-1;i<size;i++,j--)result[j]=list[i];

returnresult;}voidprintArray(intconst*list,constintsize){for(inti=0;i<size;i++)cout<<list[i]<<"";}intmain(){intlist[]={1,2,3,4,5,6};

int*pList=reverse(list,6);

printArray(pList,6);return0;}*result=newint[size];result是局部变量,退出函数存储空间被系统回收2023/5/22593.指向函数的指针

一个函数包括一组指令序列,存储在某一段内存中,这段内存空间的起始地址称为函数的入口地址称函数入口地址为函数的指针。函数名代表函数的入口地址可以定义一个指针变量,其值等于该函数的入口地址,指向这个函数,这样通过这个指针变量也能调用这个函数。这种指针变量称为指向函数的指针变量。定义指向函数的指针变量的一般形式为:

类型标识符(*指针变量名)();例如:

int(*p)();/*指针变量p可以指向一个整型函数*/float(*q)();/*指针变量q可以指向一个浮点型函数*/2023/5/2260

刚定义的指向函数的指针变量,亦象其它指针变量一样要赋以地址值才能引用。当将某个函数的入口地址赋给指向函数的指针变量,就可用该指针变量来调用所指向的函数给函数指针赋初值:将函数名(函数的入口地址值)赋给指针变量例如intm,(*p)();intmax(inta,intb);则可以p=max;/*p指向函数max()*/指针调用函数的一般形式为:

(*指针变量)(实参表);如上例:m=(*p)(12,22);/*比较m=max(12,22);*/2023/5/2261注意:

用函数指针调用函数是间接调用,没有参数类型说明,C++编译系统也无法进行类型检查,因此,在使用这种形式调用函数时要特别小心。实参一定要和指针所指函数的形参类型一致。函数指针可以作为函数参数,此时,当函数指针每次指向不同的函数时,可执行不同的函数来完成不同的功能例7.10

函数max()用来求一维数组的元素的最大值,在主调函数中用函数名调用该函数与用函数指针调用该函数来实现。2023/5/2262例7.10程序如下:#include"stdio.h"#defineM8main(){floatsumf,sump;floata[M]={11,2,-3,4.5,5,69,7,80};float(*p)();/*定义指向函数的指针p*/floatmax(floata[],intn);/*函数声明*/p=max;/*函数名(函数入口地址)赋给指针p*/sump=(*p)(a,M);/*用指针方式调用函数*/sumf=max(a,M);/*用函数名调用max()函数*/printf("sump=%.2f\n",sump);printf("sumf=%.2f\n",sumf);}floatmax(floata[],intn){intk; floats; s=a[0]; for(k=0;k<n;k++) if(s<a[k])s=a[k];returns;}2023/5/2263指向函数的指针的使用步骤:(1)

定义一个指向函数的指针变量,形如:

float(*p)();(2)

为函数指针赋值,格式如下:

p=函数名;注意:赋值时只需给出函数名,不要带参数。(3)

通过函数指针调用函数,调用格式如下:

s=(*p)(实参);2023/5/2264CaseStudies:CountingtheOccurrencesofEachLetterGenerate100lowercaselettersrandomlyandassigntoanarrayofcharacters.Counttheoccurrenceofeachletterinthearray.

2023/5/2265#include<iostream>//例7.11#include"RandomCharacter.h"usingnamespacestd;constintNUMBER_OF_LETTERS=100;char*createArray();voiddisplayArray(char[]);int*countLetters(char[]);voiddisplayCounts(int[]);intmain(){char*chars=createArray();//Declareandcreateanarraycout<<"Thelowercaselettersare:"<<endl;displayArray(chars);//Displaythearrayint*counts=countLetters(chars);//统计每个字符出现次数cout<<endl;cout<<"Theoccurrencesofeachletterare:"<<endl;displayCounts(counts);return0;}2023/5/2266char*createArray()//Createanarrayofcharacters{//Declareanarrayofcharactersandcreateitchar*chars=newchar[NUMBER_OF_LETTERS];

//Createlowercaselettersrandomlyandassignthemtothearray

srand(time(0));for(inti=0;i<NUMBER_OF_LETTERS;i++)chars[i]=getRandomLowerCaseLetter();returnchars;//Returnthearray}voiddisplayArray(charchars[])//Displaythearrayofcharacters{//Display20thecharactersoneachlinefor(inti=0;i<NUMBER_OF_LETTERS;i++){if((i+1)%20==0)cout<<chars[i]<<""<<endl;elsecout<<chars[i]<<"";}}2023/5/2267//Counttheoccurrencesofeachletterint*countLetters(charchars[]){//Declareandcreateanarrayof26intint*counts=newint[26];//创建26元素的数组,起始地址送countfor(inti=0;i<26;i++)counts[i]=0;//Initializethearray//Foreachlowercaseletterinthearray,countitfor(inti=0;i<NUMBER_OF_LETTERS;i++)counts[chars[i]-'a']++;returncounts;}voiddisplayCounts(intcounts[])//Displaycounts{for(inti=0;i<26;i++){if((i+1)%10==0)cout<<counts[i]<<""<<static_cast<char>(i+'a')<<endl;elsecout<<counts[i]<<""<<static_cast<char>(i+'a')<<"";}}2023/5/22687.9CharactersandC-StringsStringsareusedofteninprogramming.Youhaveusedstringliterals.Astringisasequenceofcharacters.TwowaystoprocessstringsinC++.Onewayistotreatstringsasarraysofcharacters.Thisisknownaspointer-basedstringsorC-strings.Theotherwayistoprocessstringsusingthestringclass.Thestringclasswillbeintroducedin§9.14.Thissectionintroducespointer-basedstrings.2023/5/2269CharacterTestFunctions2023/5/2270CaseConversionFunctions2023/5/2271例7.12#include<iostream>usingnamespacestd;intmain(){cout<<"Enteracharacter:";charch;cin>>ch;if(islower(ch)){cout<<"Itisalowercaseletter"<<endl;cout<<"Itsequivalentuppercaseletteris"<<static_cast<char>(toupper(ch))<<endl;}elseif(isupper(ch)){cout<<"Itisanuppercaseletter"<<endl;cout<<"Itsequivalentlowercaseletteris"<<static_cast<char>(tolower(ch))<<endl;}

elseif(isdigit(ch)){cout<<"Itisadigitcharacter"<<endl;}return0;}2023/5/22722.StoringandAccessingStringsApointer-basedstringinC++isanarrayofcharactersendinginthenullterminator('\0'),whichindicateswhereastringterminatesinmemory.Anarraycanbeaccessedviaapointer.Soastringcanalsobeaccessedviaapointer,whichpointstothefirstcharacterinthestring.Soyoucandeclareastringvariableusinganarrayorapointer.Thefollowingtwodeclarationsarebothfine:charcity[7]="Dallas";//Option1char*pCity="Dallas";//Option2比较两者不同2023/5/2273用字符数组存储和处理字符串注意!若有如下声明:chara[4],*p1,*p2;错误的:

a="abc";

cin>>p1;正确的:

p1="abc";

p2=a;cin>>p2;2023/5/2274PointerSyntaxYoucanaccesscityorpCityusingthearraysyntaxorpointersyntax.Forexample,cout<<city[1]<<endl;cout<<*(city+1)<<endl;cout<<pCity[1]<<endl;cout<<*(pCity+1)<<endl;eachdisplayscharactera(thesecondelementinthestring).2023/5/22753.ReadingStringsYoucanreadastringfromthekeyboardusingthecinobject.Forexample,seethefollowingcode:cout<<"Enteracity:";cin>>city;//空格作为结束输入字符,不能包含空格cout<<"Youentered"<<city<<endl;注意:

int*str;

cin>>str;//有无问题?指针str没有初始化2023/5/2276字符串的输入/输出方法逐个字符输入输出将整个字符串一次输入或输出

例:charc[]="China";

cout<<c;cin>>c;注意输出字符不包括'\0'输出字符串时,输出项是字符数组名,输出时遇到'\0'结束。输入多个字符串时,以空格分隔;输入单个字符串时其中不能有空格。2023/5/2277例如:程序中有下列语句:

staticcharstr1[5],str2[5],str3[5];cin>>str1>>str2>>str3;

运行时输入数据:

Howareyou?内存中变量状态如下:

str1:How\0str2:are\0str3:you?\0772023/5/2278若改为:

staticcharstr[13];cin>>str;

运行时输入数据:

Howareyou?内存中变量str内容如下:

str:How\0782023/5/2279ReadingStringsUsinggetlineC++providesthecin.getlinefunctionintheiostreamheaderfile,whichreadsastringintoanarray.Thesyntaxofthefunctionis:cin.getline(chararray[],intsize,chardelimitChar)Thefunctionstopsreadingcharacterswhenthedelimitercharacterisencounteredorwhenthesize-1numberofcharactersareread.Thelastcharacterinthearrayisreservedforthenullterminator('\0').

Ifthedelimiterisencountered,itisread,butnotstoredinthearray.ThethirdargumentdelimitCharhasadefaultvalue('\n').2023/5/2280整行输入字符串cin.getline(字符数组名St,字符个数N,结束符);功能:一次连续读入多个字符(可以包括空格),直到读满N-1个,或遇到指定的结束符(默认为'\n')。读入的字符串存放于字符数组St中。读取但不存储结束符。cin.get(字符数组名St,字符个数N,结束符);功能:一次连续读入多个字符(可以包括空格),直到读满N-1个,或遇到指定的结束符(默认为‘\n’)。读入的字符串存放于字符数组St中。既不读取也不存储结束符。

会留出最后一个元素保存结束字符‘\0’.2023/5/2281例7.13整行输入字符串#include<iostream>usingnamespacestd;voidmain(void){ charcity[80]; charstate[80]; inti; for(i=0;i<2;i++) {cin.getline(city,80,','); cin.getline(state,80,'\n'); cout<<"City:"<<city<<"State:"

<<state<<endl; }}Beijing,ChinaCity:BeijingCountry:ChinaShanghai,ChinaCity:ShanghaiCountry:China2023/5/22824.String

Functions

在头文件cstring中,使用字符串函数要包含该头文件

2023/5/2283#include<iostream>#include<cstring>

usingnamespacestd;intmain(){chars1[20],s2[20]="Dallas,Texas";chars3[20]="AAAAAAAAAA";

strcpy(s1,s2);strncpy(s3,s2,6);

s3[6]='\0';//Insertnullterminatorcout<<"Thestringins1is"<<s1<<endl;cout<<"Thestringins2is"<<s2<<endl;cout<<"Thestringins3is"<<s3<<endl;cout<<"Thelengthofs3is"<<strlen(s3)<<endl;return0;}例7.14StringExamplesCopystringCombinestringComparestringStringconversion2023/5/2284#include<iostream>#include<cstring>usingnamespacestd;intmain(){chars1[20]="Dallas";chars2[20]="Texas,USA";chars3[20]="Dallas";

strcat(strcat(s1,","),s2);strncat(strcat(s3,","),s2,5);cout<<"Thestringins1is"<<s1<<endl;cout<<"Thestringins2is"<<s2<<endl;cout<<"Thestringins3is"<<s3<<endl;cout<<"Thelengthofs1is"<<strlen(s1)<<endl;cout<<"Thelengthofs3is"<<strlen(s3)<<endl;return0;}strcat(s1,“,”);strcat(s1,s2);2023/5/2285#include<iostream>#include<cstring>usingnamespacestd;intmain(){char*s1="abcdefg";char*s2="abcdg";char*s3="abcdg";cout<<"strcmp(s1,s2):"<<strcmp(s1,s2)<<endl;cout<<"strcmp(s2,s1):"<<strcmp(s2,s1)<<endl;cout<<"strcmp(s2,s3):"<<strcmp(s2,s3)<<endl;cout<<"strncmp(s1,s2,3):"<<strncmp(s1,s2,3);cout<<endl;return0;}2023/5/2286#include<iostream>#include<cstring>usingnamespacestd;intmain(){cout<<atoi("43")+atoi("5")<<endl;cout<<atof("4.5")+atof("5.5")<<endl;chars[10];

itoa(42,s,8);//将42按8进制转换成字符串送Scout<<s<<endl;itoa(42,s,10);cout<<s<<endl;itoa(42,s,16);cout<<s<<endl;return0;}2023/5/22875.ObtainingSubstringsOftenitisusefultoobtainasubstringfromastring.ButthereisnosuchfunctioninC++.Youcandevelopyourownfunctionforextractingsubstrings.Theheaderofthefunctioncanbespecifiedas:char*substring(char*s,intstart,intend)2023/5/2288//Substring.hchar*substring(constchar*consts,intstart,intend){char*pNewString;pNewString=newchar[end-start+1+1];intj=0;for(inti=start;i<=end;i++,j++){pNewString[j]=s[i];}pNewString[j]='\0';//SetanullterminatorreturnpNewString;}亦可只把函数原型放substri

温馨提示

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

评论

0/150

提交评论