課件第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

提交評論