C:字符串和指針_第1頁
C:字符串和指針_第2頁
C:字符串和指針_第3頁
C:字符串和指針_第4頁
C:字符串和指針_第5頁
已閱讀5頁,還剩66頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

第二章

數(shù)組、字符串和指針

迄今為止,我們已經(jīng)學(xué)習(xí)了所有重要的基木數(shù)據(jù)類型,對于如何在程序中執(zhí)行計(jì)算和進(jìn)行

判斷也有了基本的了解。本章將擴(kuò)展前面所學(xué)的基本編程技術(shù)的應(yīng)用范圍,從此前使用單獨(dú)的

數(shù)據(jù)項(xiàng)擴(kuò)展到處理數(shù)據(jù)項(xiàng)的整個(gè)集合。木章將講述以下內(nèi)容:

?數(shù)組及其使用方法

?如何聲明和初始化不同類型的數(shù)組

?如何聲明和使用多維數(shù)組

?指針及其使用方法

?如何聲明和初始化不同類型的指針

?數(shù)組和指針之間的關(guān)系

?引用的概念及聲明方法,關(guān)于使用引用的幾點(diǎn)初步建議

?如何在本地C++程序中給變量動(dòng)態(tài)分配內(nèi)存

?如何在CLR程序中動(dòng)態(tài)分配內(nèi)存

?跟蹤句柄和跟蹤引用的概念,CLR程序中需要它們的原因

?如何在C++/CLI程序中處理字符串和數(shù)組

?內(nèi)部指針的概念,創(chuàng)建和使用內(nèi)部指針的方法

本章將更多地使用對象,我們還沒有詳細(xì)分析如何創(chuàng)建對象,因此即使對此一無所知也不

必?fù)?dān)心。我們將從第7章開始詳細(xì)學(xué)習(xí)類和對象。

4.1處理多個(gè)相同類型的數(shù)據(jù)值

我們已經(jīng)知道如何聲明和初始化那些僅容納單項(xiàng)信息的各種類型的變量一本書稱之為數(shù)

據(jù)元素。我們知道如何在char類型的變量中創(chuàng)建一個(gè)字符,如何在short、int或long類型的變

量中創(chuàng)建一個(gè)整數(shù),如何在float或double類型的變量中創(chuàng)建一個(gè)浮點(diǎn)數(shù)。最容易想到的對這

些技術(shù)的擴(kuò)展是用單個(gè)變量名引用特定類型的多個(gè)數(shù)據(jù)元素,這樣我們將能夠處理更寬范圍的

應(yīng)用問題。

在下面這個(gè)例子中,我們就需要這種技術(shù)。假設(shè)需要編寫工資計(jì)算程序。為每個(gè)人的工資、

應(yīng)繳稅款等信息使用單獨(dú)命名的變量,這是一項(xiàng)艱巨的任務(wù)。處理此類問題的簡便方法是使用

第4章數(shù)組、字符串和指針

某種類屬名(比如employeeName)來引用員工,用其他類屬名來引用與各個(gè)員工有關(guān)的數(shù)據(jù),比

如工資、應(yīng)繳稅款等。當(dāng)然,我們還需要一種從全體員工中挑選出個(gè)別員工的方法,以及從相

關(guān)的同類變量中挑選出數(shù)據(jù)的方法。這種需求隨著程序中出現(xiàn)要處理的相似實(shí)體的集合而出

現(xiàn),這些實(shí)體可能是棒球運(yùn)動(dòng)員,也可能是戰(zhàn)艦。自然,C++給我們提供了處理集合的方法。

4.1.1數(shù)組

在ISO/ANSIC++中,數(shù)組是所有此類問題解決方案的基礎(chǔ)。數(shù)組就是一組名為數(shù)組元素

或簡稱元素的存儲單元,各個(gè)存儲單元可以存儲相同數(shù)據(jù)類型的數(shù)據(jù)項(xiàng),而我們可以用相同的

變量名引用所有存儲單元。工資計(jì)算程序中員工姓名就可以存儲在一個(gè)數(shù)組中,各員工的工資

可以存儲在另一個(gè)數(shù)組中,而應(yīng)繳稅款可存儲在第三個(gè)數(shù)組中。

數(shù)組中各個(gè)數(shù)據(jù)項(xiàng)用索引值進(jìn)行標(biāo)識;索引值就是表示數(shù)組元素編號的整數(shù)。第一個(gè)元素

的編號是0,第二個(gè)是1,依此類推。我們也可以將數(shù)組元素的索引值視為相對于數(shù)組中第一

個(gè)元素的偏移量。第一個(gè)元素的偏移量是0,因此其索引值是0,索引值3指的是第四個(gè)數(shù)組

元素。對工資計(jì)算程序來說,我們應(yīng)該這樣安排那3個(gè)數(shù)組:如果某個(gè)員工的姓名存儲在

employeeName數(shù)組中特定索引值標(biāo)識的單元,則pay和tax數(shù)組應(yīng)該在相同索引值引用的數(shù)組

位置存儲該員工的工資和應(yīng)繳稅款數(shù)據(jù)。

數(shù)組的基本結(jié)構(gòu)如圖4」所示。

第2個(gè)元素的索引值第5個(gè)元素的索引值

數(shù)姐名一數(shù)組名一

hcig}it{0]height[O]heiglit[O]height[0]height[O]heightfO]

736251424134

height數(shù)組包含6個(gè)元素

圖4-1

圖4-1是一個(gè)數(shù)組的結(jié)構(gòu)圖。數(shù)組height有6個(gè)元素,各元素存儲不同的數(shù)值。這些數(shù)值

是某個(gè)家庭中所有成員的身高(精確到英寸)。因?yàn)橛?個(gè)元素,所以索引值為0~5。如果要引

用某個(gè)元素,則應(yīng)該先寫出數(shù)組名稱,然后在方括號內(nèi)寫上該元素的索引值。例如,height⑵

將引用第三個(gè)元素。如果將索引值看作相對于第一個(gè)元素的偏移量,則很容易理解第四個(gè)元素

的索引值是3。

存儲各個(gè)元素所需存儲單元的數(shù)量取決于元素的類型,數(shù)組的所有元素都存儲在連續(xù)的內(nèi)

存區(qū)域中。

4.1.2聲明數(shù)組

數(shù)組的聲明方法基本上與此前所看到的變量聲明的方法相同,唯?區(qū)別是應(yīng)該在緊跟數(shù)組

135

VisualC++2008入門經(jīng)典

名的方括號內(nèi)指出數(shù)組元素的數(shù)量。例如,我們可以用下面這條聲明語句,聲明圖4-1中的整

數(shù)數(shù)組height:

longheight[6];

因?yàn)槊總€(gè)long數(shù)值在內(nèi)存中要占用4個(gè)字節(jié),所以整個(gè)數(shù)組共需24個(gè)字節(jié)。數(shù)組長度只

受運(yùn)行該程序的計(jì)算機(jī)上內(nèi)存總量的限制。

數(shù)組可以被聲明成任意類型。例如,我們可以用下面這條語句,聲明兩個(gè)用來存儲一組發(fā)

動(dòng)機(jī)的體積和功率的數(shù)組:

doublecubic_inches[10];//Enginesize

doublehorsepower[10];//Enginepoweroutput

這兩個(gè)數(shù)組可存儲10臺發(fā)動(dòng)機(jī)的體積和功率,其索引值為0-9.正如前面在其他變量的聲

明語句中所看到的那樣,我們可以用?條語句聲明多個(gè)同類型的數(shù)組,但實(shí)踐中在分開的語句

中聲明變量往往更合適。

試一試:使用數(shù)組

為練習(xí)如何使用數(shù)組,假設(shè)我們需要記錄每次給汽車購買的汽油量和相應(yīng)的里程表讀數(shù)。

我們可以編寫程序來分析這些數(shù)據(jù),以了解不同時(shí)間段的汽油消耗情況。

//Ex4_01.cpp

//Calculatinggasmileage

#include<iostream>

#include<iomanip>

usingstd::cin;

usingstd::cout;

usingstd::endl;

usingstd::setw;

intmain()

(

constintMAX=20;//Maximumnumberofvalues

doublegas[MAX];//Gasquantityingallons

longmiles[MAX];//Odometerreadings

intcount=0;//Loopcounter

charindicator=*y';//Inputindicator

while((indicator=='y'||indicator=='Y,)&&count<MAX)

cout<<endl

<<"Entergasquantity:n;

cin>>gas[count];//Readgasquantity

cout<<"Enterodometerreading:";

cin>>miles[count];//Readodometervalue

++count;

cout<<"Doyouwanttoenteranother(yorn)?

cin>>indicator;

if(count<=1)//count=1after1entrycompleted

//...weneedatleast2

136

第4章數(shù)組、字符串和指針

cout<<endl

<<nSorry-atleasttworeadingsarenecessary.n;

return0;

}

//Outputresultsfrom2ndentrytolastentry

for(inti=1;i<count;i++)

cout<<endl

<<setw(2)<<i<<//Outputsequencenumber

<<"Gaspurchased="<<gas[i]<<"gallons,1//Outputgas

<<nresultedin*'//Outputmilespergallon

<<(miles[i]-miles[i-1])/gas[i]<<"milespergallon.";

cout<<endl;

return0;

程序假設(shè)每次都給油箱加滿汽油,因此購買的汽油量就是行駛的里程所需的汽油消耗量。

下面是本程序產(chǎn)生的輸出:

Entergasquantity:12.8

Enterodometerreading:25832

Doyouwanttoenteranother(yorn)?y

Entergasquantity:14.9

Enterodometerreading:26337

Doyouwanttoenteranother(yorn)?y

Entergasquantity:11.8

Enterodometerreading:26598

Doyouwanttoenteranother(y

1.Gaspurchased=14.9gallonsresultedin33.8926milespergallon.

2.Gaspurchased=11.8gallonsresultedin22.1186milespergallon.

示例說明

因?yàn)楸仨毜玫絻纱卫锍瘫碜x數(shù)的差值,才能計(jì)算用掉的汽油所能行駛的里程,所以我們只

使用第一對輸入值的里程表讀數(shù),而忽略第一次購買的汽油量,這些汽油是在以前行駛的路程

中消耗掉的。

在輸出中顯示的第二段時(shí)間內(nèi),交通狀況必定相當(dāng)糟糕,或者是經(jīng)常踩剎車。

用來存儲輸入數(shù)據(jù)的兩個(gè)數(shù)組gas和miles的大小取決于常量MAX。通過改變MAX的值,

我們即可使該程序適應(yīng)最大數(shù)量不同的輸入值集合。這種技術(shù)經(jīng)常用來使程序靈活地適應(yīng)要處

理的信息量。當(dāng)然,編寫程序代碼時(shí)必須考慮到const變量指定的數(shù)組大小或任何其他參數(shù)。

不過,上述要求增加的難度不算大,因此沒有任何理由不采用這種技術(shù)。我們稍后還將學(xué)習(xí)如

何在程序執(zhí)行時(shí)動(dòng)態(tài)分配內(nèi)存,從而不必再預(yù)先給數(shù)據(jù)分配固定數(shù)量的內(nèi)存。

輸入數(shù)據(jù)

while循環(huán)讀取數(shù)據(jù)值。因?yàn)檠h(huán)變量的范圍是從0到MAX-L所以該程序不允許其用

戶輸入超過數(shù)組容量的數(shù)據(jù)量。程序分別將變量count和indicator初始化為0和y,因此while

循環(huán)至少執(zhí)行-次。程序提示用戶輸入要求的各個(gè)數(shù)值,然后將輸入值讀入適當(dāng)?shù)臄?shù)組元素中。

用來存儲具體數(shù)值的元素由變量count確定,第一次輸入時(shí)該變量是0。我們以count作為索引

值,在cin語句中指定數(shù)組元素,然后使count力口1,從而為下次輸入做好準(zhǔn)備。

137

VisualC++2008入門經(jīng)典

輸入各個(gè)數(shù)值之后,程序提示用戶確認(rèn)是否要輸入另外的數(shù)值。輸入的字符被讀入indicator

變量中,然后在循環(huán)條件中進(jìn)行測試。如果沒有輸入y或Y,則循環(huán)終止,變量count小于指

定的最大值MAX。

輸入循環(huán)結(jié)束以后(無論通過什么方法),count的值將比每個(gè)數(shù)組中最后輸入的元素的索引

值大1(記住,我們每次輸入新元素之后都使該變量加1)。檢查該變量可以驗(yàn)證是否至少輸入

了兩對數(shù)值。如果不是,則程序?qū)⒁砸粭l適當(dāng)?shù)南⒔Y(jié)束,因?yàn)橛?jì)算里程至少需要兩個(gè)里程表

讀數(shù)。

生成結(jié)果

輸出是在for循環(huán)中產(chǎn)生的??刂谱兞縤從1變化到count-I,使程序計(jì)算當(dāng)前元素miles[i]

和前一個(gè)元素miles[i-1]之間的差值,以作為本次行駛的里程。注意,數(shù)組的索引值可以是任

何結(jié)果為整數(shù)的表達(dá)式,前提是該整數(shù)是相應(yīng)數(shù)組的合法索引值一即從0到數(shù)組元素的數(shù)量

減lo

如果索引表達(dá)式的值不在對應(yīng)于合法數(shù)組元素的范圍之內(nèi),那么程序?qū)⒁靡粋€(gè)錯(cuò)誤的存

儲單元,其中可能包含其他數(shù)據(jù)、無用信息甚至程序代碼。如果對錯(cuò)誤元素的引用出現(xiàn)在表達(dá)

式中,則程序?qū)⑹褂秒S機(jī)的一個(gè)數(shù)據(jù)值進(jìn)行計(jì)算,這當(dāng)然會產(chǎn)生意外結(jié)果。如果需要將某種結(jié)

果存儲在數(shù)組元素中,但使用的是非法索引值,則將覆蓋位于該存儲單元的任何數(shù)據(jù)。如果被

破壞的數(shù)據(jù)是程序代碼的組成部分,則結(jié)果是災(zāi)難性的。當(dāng)我們使用非法索引值時(shí),編譯或運(yùn)

行過程中并沒有任何警告產(chǎn)生。唯一能夠避免此類錯(cuò)誤的方法是用程序代碼來防止其發(fā)生。

cout語句為除第一對以外的所有輸入值生成輸出。程序還使用循環(huán)控制變量i,為每行輸

出生成一個(gè)行號。每加侖汽油行駛的英里數(shù)是在輸出語句中直接計(jì)算的。在表達(dá)式中使用數(shù)組

元素的方式與使用任何其他變量完全相同。

4.1.3初始化數(shù)組

為了在聲明時(shí)初始化數(shù)組,我們應(yīng)該將逗號分開的初始化數(shù)值放入大括號內(nèi),然后將這樣

的初值集合放在數(shù)組名后面的等號之后。卜面是聲明并初始化數(shù)組的示例:

intcubic_inches[5]=(200,250,300,350,400);

該數(shù)組的名稱是cubijinches,包括5個(gè)元素,各存儲一個(gè)int型數(shù)值。大括號內(nèi)初始化列

表中的數(shù)值對應(yīng)于連續(xù)的數(shù)組索引值,因此cubijinches⑼的值是200,cubic_inches[l]的值是

250,cubic_inches[2]的值是300,依此類推。

指定的初始化數(shù)值不能比數(shù)組的元素多,但可以比數(shù)組的元素少。如果少,則列表中的初

值被分配給從第一個(gè)元素(對應(yīng)于索引值0)開始的連續(xù)元素。那些沒有得到初值的數(shù)組元素被初

始化為0。如果根本沒有提供初始化列表,則情況就不是這樣。如果沒有初始化列表,數(shù)組元

素包含的將是無用數(shù)據(jù)。另外,如果我們使用初始化列表,則列表內(nèi)必須至少包括一個(gè)初值,

否則編譯器將生成?條出錯(cuò)消息。下面這個(gè)示例用來說明數(shù)組的初始化方法。

試一試:初始化數(shù)組

//Ex4_02.cpp

//Demonstratingarrayinitialization

#include<iostream>

138

第4章數(shù)組、字符串和指針

#include<iomanip>

usingstd::cout;

usingstd::endl;

usingstd::setw;

intmain()

I

intvalue[5]={1,2,3};

intjunk[5];

cout<<endl;

for(inti=0;i<5;i++)

cout<<setw(12)<<value[i];

cout<<endl;

for(inti=0;i<5;i++)

cout<<setw(12)<<junk[i];

cout<<endl;

return0;

}

該示例聲明了兩個(gè)數(shù)組。第一個(gè)數(shù)組value被部分初始化,但第二個(gè)數(shù)組junk完全沒有被

初始化。該程序生成兩行輸出,筆者計(jì)算機(jī)上的輸出結(jié)果如下:

12300

-858993460-858993460-858993460-858993460-858993460

在您的計(jì)算機(jī)上,第二行值(對應(yīng)于junk[OJ到j(luò)unk[4]的值)可能完全不同。

示例說明

數(shù)組value的前3個(gè)數(shù)值是初值,后兩個(gè)是默認(rèn)值0。在junk數(shù)組中,所有數(shù)值都是荒謬

的,因?yàn)槲覀兏緵]有提供任何初值。那些數(shù)組元素保留著上次使用這些存儲單元的程序遺留

下來的內(nèi)容。

將整個(gè)數(shù)組初始化為0的便捷方法是僅指定?個(gè)初值0。例如:

longdata[100]={0};//Initializeallelementstozero

這條語句聲明數(shù)組data,并將全部100個(gè)元素初始化為0。第一個(gè)元素是用大括號內(nèi)的數(shù)

值初始化的,其余元素因語句中省略了相應(yīng)的初值而被初始化為0.

倘若提供初值的話,我們還可以省略數(shù)值型數(shù)組的長度。數(shù)組元素的數(shù)量由指定的初值數(shù)

量決定。例如,數(shù)組聲明語句

intvalue[]={2,3,4};

定義的數(shù)組有3個(gè)元素,初值分別是2、3和4。

4.1.4字符數(shù)組和字符串處理

char類型的數(shù)組被稱作字符數(shù)組,通常用來存儲字符串。字符串是附加有特殊字符(串尾標(biāo)

志)的字符序列。串終止字符表明字符串已經(jīng)結(jié)束,該字符由轉(zhuǎn)義序列'\0'定義,有時(shí)被稱為

139

VisualC++2008入門經(jīng)典

空字符,占用一個(gè)字節(jié),其中8位全為0。這種形式的字符串經(jīng)常被稱作C型字符串,因?yàn)橐?/p>

這樣的方式定義字符串是在C語言中推出的,后來BjarneStroustrup以C語言為基礎(chǔ)開發(fā)出了

C++。這不是唯一能用的字符串表示法,本書稍后將介紹其他表示方法。特別需要指出的是,

C++/CLI程序使用一種不同的字符串表示法,而MFC定義了表示字符串的CString類。

C型字符串在內(nèi)存中的表不如圖4-2所不。

name[4]字符串終止字符

字符串中的每個(gè)字符占用1個(gè)字節(jié)AlbertEinstein\0

charname[尸'AlbertEinstein”

圖4-2

圖4-2說明了內(nèi)存中字符的表示形式,同時(shí)給出種我們即將討論的的字符串聲明形式。

注意:

字符串中每個(gè)字符占用一個(gè)字節(jié),因此算上最后的空字符,字符串需要的字節(jié)數(shù)要比包含

的字符數(shù)多一個(gè)。

我們可以用字符串字面值來聲明并初始化字符數(shù)組。例如:

charmovie_star[15]="MarilynMonroe";

注意,終止字符'\0'是編譯器自動(dòng)添加的。如果在該字面值中顯式添加‘\0',則最終將

得到兩個(gè)空字符。但是,我們給字符數(shù)組指定元素?cái)?shù)量時(shí)必須考慮到終止字符的存在。

如圖4-1所示,我們可以讓編譯器來算出已初始化的數(shù)組的長度。下面是另一個(gè)示例:

charpresident[]="UlyssesGrant";

因?yàn)殚L度沒有指定,所以編譯器將分配足夠的內(nèi)存空間來容納該初始化字符串及終止字

符。在本例中,編譯器將給數(shù)組president分配14個(gè)元素。當(dāng)然,如果希望稍后使用該數(shù)組來

存儲另一個(gè)字符串,則其長度(包括終止空字符)不能超過14個(gè)字節(jié)。通常,確保數(shù)組足以存儲

隨后希望存儲的任何字符串是編程人員的職責(zé)。

我們也可以創(chuàng)建由Unicode字符組成的字符串,字符串中的字符類型為wchajt。下面是一

個(gè)創(chuàng)建Unicode字符串的語句:

wchar_tpresident[]=L"UlyssesGrant";

前綴L表示字符串字面值是一個(gè)寬字符串,因此字符串中的每個(gè)字符(包括終止空字符)都

會占兩個(gè)字節(jié)。當(dāng)然,對字符串的索引會引用字符,而不是字節(jié),因此president⑵對應(yīng)于字符

L'/o

140

第4章數(shù)組、字符串和指針

1.字符串輸入

<iostream>頭文件包含許多從鍵盤上讀取字符的函數(shù)定義。下面將看到的是getline()函數(shù),

該函數(shù)讀取從鍵盤輸入的字符序列,并將其以字符串形式(以'\0'字符終止)存入字符數(shù)組中。我

們通常像下面這樣使用getline。函數(shù):

constintMAX=80;//Maximumstringlengthincluding\0

charname[MAX];//Arraytostoreastring

cin.getline(name,MAX,*\n');//Readinputlineasastring

這些語句首先聲明?個(gè)有MAX個(gè)元素的char型數(shù)組name,然后使用getline。函數(shù)從cin

中讀取字符。如上所示,數(shù)據(jù)源cin與函數(shù)名稱之間有一個(gè)句點(diǎn)。句點(diǎn)表示我們在調(diào)用的getline。

函數(shù)屬于cin對象之-ogetline。函數(shù)中各參數(shù)的意義在圖4-3中給出。

要讀取的字符的最大數(shù)量.當(dāng)讀

取了最大數(shù)量的字符數(shù)后,停止結(jié)束輸入過程的字符.在此可以

輸入指定任一字符,且該字符在首次

charQ類型數(shù)組的名稱.出現(xiàn)時(shí)就將結(jié)束輸入過程

從cin讀取的字符存儲

在該數(shù)組中

cin.getline(name.MAX.W);

圖4-3

因?yàn)間etline()函數(shù)的最后一個(gè)參數(shù)是Arf(換行符或行結(jié)束字符),而第二個(gè)參數(shù)是MAX,所

以如果讀至字符,或者已經(jīng)讀入MAX-1個(gè)字符,則無論哪種情況先發(fā)生,都停止從cin讀

取字符。可讀取的最大數(shù)量是MAX-1而不是MAX,因?yàn)閿?shù)組中存儲的字符序列要附加

字符。在鍵盤上按鍵將產(chǎn)生'\n'字符,因此它通常是最方便的使輸入終止的字符。當(dāng)

然,我們可以通過改變最后一個(gè)參數(shù)而指定其他字符。輸入數(shù)組name中不存儲3字符,但前

面曾經(jīng)說過,‘\0'字符將附加到數(shù)組中輸入字符串的尾部。

稍后討論類時(shí),我們將學(xué)習(xí)更多與這種語法形式有關(guān)的知識。在此期間,我們只需視之為

理所當(dāng)然,并在示例中使用它即可。

試一試:編程處理字符串

現(xiàn)在,我們已經(jīng)有足夠的知識來編寫一個(gè)讀取字符串并計(jì)算其中包含多少字符的簡單

程序。

//Ex4_03.cpp

//Countingstringcharacters

#include<iostream>

usingstd::cin;

usingstd::cout;

usingstd::endl;

intmain()

141

VisualC++2008入門經(jīng)典

constintMAX=80;//Maximumarraydimension

charbuffer[MAX];//Inputbuffer

intcount=0;//Charactercount

cout<<"Enterastringoflessthan80characters:\nM;

cin.getline(buffer,MAX,*\n*);//Readastringuntil\n

while(buffer[count]!='\0*)//Incrementcountaslongas

count++;//thecurrentcharacterisnotnull

cout<<endl

<<"Thestring\""<<buffer

<<n\nhasn<<count<<ncharacters.M;

cout<<endl;

return0;

)

該程序的典型輸出如下所示:

Enterastringoflessthan80characters:

Radiationfadesyourgenes

Thestring"Radiationfadesyourgenes"has26characters.

示例說明

該程序首先聲明?個(gè)字符數(shù)組buffer,然后顯示條提示用戶輸入的消息,之后將從鍵盤

輸入的字符串讀入到buffer數(shù)組中。當(dāng)用戶按下鍵,或者已經(jīng)讀入MAX-1個(gè)字符時(shí),

則結(jié)束從鍵盤讀取字符的操作。

while循環(huán)用來計(jì)算輸入字符的個(gè)數(shù)。只要buffer[count]引用的當(dāng)前字符不是、0,,該循環(huán)就

繼續(xù)執(zhí)行。像這樣一邊在數(shù)組中逐步前進(jìn),一邊檢查當(dāng)前的字符,是本地C++程序中常見的一-

種技術(shù)。該循環(huán)中的唯一動(dòng)作是每看到一個(gè)非空字符,就使count力口1。

注意:

庫函數(shù)strlen()的功能和該循環(huán)的功能相同,這個(gè)函數(shù)將在本章后面介紹。

在示例的最后,我們用一條輸出語句來顯示輸入的字符串和字符數(shù)量。注意,使用轉(zhuǎn)義字

符是為了輸出雙引號。

4.1.5多維數(shù)組

迄今為止,我們定義過的數(shù)組都只有一個(gè)索引值,它們被稱為一維數(shù)組。數(shù)組還可以有多

個(gè)索引值,這樣的數(shù)組被稱作多維數(shù)組。假設(shè)有一塊農(nóng)田,我們在上面種植了豆類作物,每行

10株,共12行(因此總共有120株)。我們可以使用下面這條語句,聲明一個(gè)數(shù)組來記錄每株作

物的產(chǎn)量:

doublebeans[12][10];

這條語句聲明了一個(gè)二維數(shù)組beans,第一個(gè)索引值是行號,第二個(gè)索引值是行內(nèi)的編號。

引用任何一個(gè)元素都需要兩個(gè)索引值。例如,我們可以用卜面的語句,設(shè)定對應(yīng)于第三行第五

142

第4章數(shù)組、字符串和指針

株作物的那個(gè)元素的值。

beans(2][4]=10.7;

記住,索引值是從。開始的,因此行索引值是2,行內(nèi)第五株作物的索引值是4。

農(nóng)民可能有好幾塊相同的農(nóng)田,上面以相同的模式種植著豆類作物。假設(shè)有8塊農(nóng)田,那

么可以用三維數(shù)組來記錄產(chǎn)量,其聲明語句如下:

doublebeans[8][12][10];

該數(shù)組可以記錄每塊農(nóng)田內(nèi)所有作物的產(chǎn)量,最左邊的索引值引用具體的田塊。如果我們

的豆類種植業(yè)已經(jīng)達(dá)到國際規(guī)模,則可以使用四維數(shù)組,增加的那一維用來表示國家。

數(shù)組在內(nèi)存中的存儲方式是使最右邊的索引值最快地變化。因此,數(shù)組data[3][4]是3個(gè)各

自包含4個(gè)元素的一維數(shù)組。該數(shù)組的排列如圖4-4所示。

正如圖4-4中的箭頭所指示的那樣,數(shù)組元素存儲在連續(xù)的內(nèi)存區(qū)域中。第一個(gè)索引值選

擇數(shù)組的某一行,第二個(gè)索引值選擇這一行內(nèi)的元素。

注意,木地C++中的二維數(shù)組實(shí)際上是一維數(shù)組的一維數(shù)組。三維的木地C++數(shù)組實(shí)際上

也是一維數(shù)組,其中各個(gè)元素又都是一維數(shù)組的一維數(shù)組。多數(shù)時(shí)候,這不是我們需要擔(dān)心的

事情,但正如稍后將看到的那樣,C++/CLI數(shù)組不是這樣。就圖4-4中的數(shù)組而言,這意味著

表達(dá)式data[0]、data[lj和data[2]都是一維數(shù)組。

圖4-4

1.初始化多維數(shù)組

為了初始化多維數(shù)組,我們需要擴(kuò)展原來初始化一維數(shù)組的方法。例如,我們可以用下面

這條聲明語句初始化二維數(shù)組data:

longdata[2][4]={

(1,2,3,5),

{7,11,13,17}

);

如上所示,該數(shù)組中每行的初值都被包圍在各自的大括號內(nèi)。因?yàn)槊啃杏?個(gè)元素,所以

143

VisualC++2008入門經(jīng)典

每組有4個(gè)初值,因?yàn)閐ata數(shù)組共有兩行,所以外層大括號內(nèi)共有兩組初值,組與組之間用逗

號分開。

我們可以在某行內(nèi)省略某些初值,這樣未獲得初值的數(shù)組元素將被初始化為0。例如:

longdata[2][4]={

{1,2,3},

{7Z11}

);

上面為省略掉的初值留出了空間,以便使讀者看清省略初值的位置。元素data[0][3],

data[lH2]和data[l]⑶沒有初值,因此值是0。

如果希望將整個(gè)數(shù)組初始化為0,我們只需寫成:

longdata[2][4]={0};

如果要初始化更多維的數(shù)組,則記住一點(diǎn):數(shù)組中有多少維,初值組就需要多少層嵌套的

大括號。

試一試:存儲多個(gè)字符串

我們可以使用單個(gè)二維數(shù)組存儲多個(gè)C型字符串。下面就是?個(gè)這樣的示例程序:

//Ex4_04.cpp

//Storingstringsinanarray.

#include<iostream>

usingstd::cout;

usingstd::cin;

usingstd::endl;

intmain()

(

charstars[6][80]={"RobertRedford",

"HopalongCassidy",

??Lassie',,

"SlimPickensn,

"BorisKarloffn,

"OliverHardy"

};

intdice=0;

cout<<endl

<<”Pickaluckystar!n

<<"Enteranumberbetween1and6:

cin>>dice;

if(dice>=1&&dice<=6)//Checkinputvalidity

cout<<endl//Outputstarname

<<"Yourluckystaris<<stars[dice-1];

else

cout<<endl//Invalidinput

<<"Sorry,youhaven*ttaluckystar.n;

cout<<endl;

return0;

144

第4章數(shù)組、字符串和指針

示例說明

本示例的要點(diǎn)是數(shù)組stars的聲明。stars是二維數(shù)組,元素的類型為char,該數(shù)組可以容納

6個(gè)字符串,各字符串可包含80個(gè)字符(包括編譯器自動(dòng)添加的終止空字符)。該數(shù)組的初始化

字符串被包圍在大括號之間,相互以逗號分開。

注意:

以這種方式使用數(shù)組的塊點(diǎn)之一,是幾乎總有一些未被使用的存儲單元。本例中所有字符

串都小于80個(gè)字符,因此數(shù)組中各行剩余的元素都被白白浪費(fèi)掉了。

我們也可以省略數(shù)組第一維的大小,而讓編譯器來算出有多少個(gè)字符串,聲明如下:

charstars[][80]={MRobertRedford",

"HopalongCassidy",

"Lassie",

"SlimPickens",

°BorisKarloff",

"OliverHardy"

);

這樣聲明將使編譯器根據(jù)指定的初始化字符串的個(gè)數(shù)確定第一維的大小。因?yàn)橛?個(gè)字符

串,所以結(jié)果是完全相同的,但是這樣可以避免出錯(cuò)的可能性。在這里,我們不能將第二維也

省略掉。在二維或者多維數(shù)組中,最右邊的一維必須是確定的。

注意:

這條聲明語句最后的分號不能省略。當(dāng)為數(shù)組提供初值時(shí),人們很容易忘記應(yīng)該以分號結(jié)束。

在下面語句中需要引用某個(gè)字符串的位置,我們只需指定第一個(gè)索引值:

cout<<endl//Outputstarname

<<"Yourluckystaris”<<stars[dice-1];

單個(gè)索引值將選擇特定的有80個(gè)元素的子數(shù)組,輸出操作將顯示出子數(shù)組中終止空字符

之前的所有內(nèi)容。指定的索引值是dice-1,因?yàn)閐ice的值是從1~6,而索引值無疑應(yīng)該是從

0-5.

4.2間接數(shù)據(jù)存取

前面討論的變量使我們能夠命名某個(gè)存儲單元,然后在其中存儲特定類型的數(shù)據(jù)。變量的

內(nèi)容或者是從某種外部設(shè)備(比如鍵盤)輸入的,或者是根據(jù)其他輸入的數(shù)值計(jì)算出來的。C++

中還有一種變量不存儲輸入或計(jì)算出來的數(shù)據(jù),但卻大大擴(kuò)充了程序的功能和靈活性。此類變

量被稱為指針。

4.2.1指針的概念

用來存儲數(shù)據(jù)的各個(gè)存儲單元都有地址。地址給PC硬件提供了引用具體數(shù)據(jù)項(xiàng)的途徑。

145

VisualC++2008入門經(jīng)典

指針變量存儲特定類型的另一個(gè)變量的地址。就像其他變量一樣,指針變量也有名稱,而且指

針還有類型,以指出其內(nèi)容引用的是什么類型的變量。注意,指針變量的類型隱含著該變量是

指針的事實(shí)。如果某個(gè)指針變量的內(nèi)容是包含int類型數(shù)值的存儲單元的地址,則該變量的類

型是“指向int類型的指針”。

4.2.2聲明指針

除了在名稱前面用星號表明是指針變量以外,指針的聲明與普通變量類似。例如,為了聲

明long類型的指針pnumber,我們可以使用下面的語句:

long*pnumber;

該語句中星號離類型名稱更近。如果愿意,我們也可以將其寫成下面的形式:

long*pnumber;

編譯器根本不介意我們怎樣寫,但變量pnumber的類型是“指向long類型的指針”,因此

使星號離類型名稱更近往往能更清楚地表明這一點(diǎn)。無論選擇哪種書寫指針類型的方法,結(jié)果

都相同。

我們可以在同一條語句中混合普通變量和指針的聲明。例如:

long*pnumber,number=99;

像前面一樣,這條語句聲明了變量pnumber,其類型為“指向long類型的指針”,同時(shí)還

聲明了long類型的變量number。一般來說,將指針的聲明同其他變量分開更好,不然可能使

人對所聲明變量的類型產(chǎn)生誤解一尤其當(dāng)星號離類型名稱更近時(shí)。下面的語句看起來更清楚,

而且將聲明分開寫在兩行上使我們能夠分別給它們添加注釋,這有助于使程序更易于理解。

longnumber=99;//Declarationandinitializationoflongvariable

long*pnumber;//Declarationofvariableoftypepointertolong

在C++中,使用以字母p開始的變量名表示指針是通用慣例,這使我們能更容易看清程序

中哪些變量是指針,從而使程序更易于理解。

下面我們先舉例說明指針的工作過程,暫時(shí)先不管指針有什么用途。我們很快就將學(xué)習(xí)如

何使用指針。假設(shè)有一個(gè)long類型的變量number(上面聲明過),其包含的數(shù)值是99,還有一

個(gè)變量pnumber,其類型為“指向long類型的指針”,可用來存儲變量number的地址。但是,

我們?nèi)绾潍@得變量的地址呢?

取址運(yùn)算符

我們需要的是取址運(yùn)算符&。該運(yùn)算符是一元運(yùn)算符,用于獲得變量的地址,又名引用運(yùn)

算符一本章稍后再討論如此命名的原因。為了設(shè)置剛才討論的指針,可以使用下面這條賦值

語句:

pnumber=&number;//Storeaddressofnumberinpnumber

該操作的結(jié)果如圖4-5所示。

我們可以使用&運(yùn)算符獲得任何變量的地址,但需要有適當(dāng)類型的指針來存儲地址。例如,

146

第4章數(shù)組、字符串和指針

如果我們希望存儲double型變量的地址,則相應(yīng)的指針必須被聲明為double*類型,即“指向

double類型的指針”。

&number?

Address:1008

pnumbernumber

1008.99

pnumber=&number;

圖4-5

4.2.3使用指針

如何獲得變量的地址,并將其存入某個(gè)指針變量都已經(jīng)講解清楚了,但真正有趣的是如何

使用指針。指針的重要用途是存取指針?biāo)缸兞恐械臄?shù)據(jù)值,這需要使用間接運(yùn)算符*。

1.間接運(yùn)算符

將間接運(yùn)算符*與某個(gè)指針一起使用,可以存取該指針指向的變量的內(nèi)容。“間接運(yùn)算符”

的名稱源于間接存取數(shù)據(jù)的事實(shí)。該運(yùn)算符又名解除引用運(yùn)算符,而存取指針?biāo)傅淖兞恐袛?shù)

據(jù)的過程被稱為解除對指針的引用。

該運(yùn)算符可能使人混淆,因?yàn)橄嗤姆?現(xiàn)在有多種不同用途。星號*是乘法運(yùn)算符,還

是間接運(yùn)算符,此外還用于指針的聲明。我們每次使用*符號時(shí),編譯器都能根據(jù)I:下文區(qū)分

其意義。當(dāng)我們使兩個(gè)變量相乘時(shí)一比如A*B,該表達(dá)式除了是乘法操作以外,沒有任何其

他有意義的解釋。

2.需要使用指針的原因

為什么一定要使用指針?畢竟,取出我們已經(jīng)知道的某個(gè)變量的地址,然后將其放入某個(gè)

指針內(nèi),以便能夠解除對該指針的引用,看起來似乎是完全不必要的額外開銷。但指針實(shí)際上

非常重要,原因不止?種。

我們可以使用指針符號處理數(shù)組中存儲的數(shù)據(jù),相應(yīng)的執(zhí)行速度往往比使用數(shù)組符號要

快。另外,當(dāng)我們稍后學(xué)習(xí)如何定義自己的函數(shù)時(shí),將看到指針被廣泛使用,以便能夠在函數(shù)

內(nèi)部訪問在函數(shù)外部定義的大塊數(shù)據(jù)——比如數(shù)組。但最重要的一點(diǎn)是使我們能夠動(dòng)態(tài)地一

即在程序執(zhí)行過程中,給變量分配存儲空間。這種功能使程序可以根據(jù)實(shí)際的輸入,來調(diào)整自

己的內(nèi)存使用量。因?yàn)槲覀冾A(yù)先不知道將動(dòng)態(tài)創(chuàng)建多少個(gè)變量,所以首選方法是使用指針。因

此,我們應(yīng)該確保真正掌握指針的用法。

147

VisualC++2008入門經(jīng)典

在下面的示例中,我們可以試一試指針操作的各種用法。

//Ex4_05.cpp

//Exercisingpointers

#include<iostream>

usingstd::cout;

usingstd::endl;

usingstd::hex;

usingstd::dec;

intmain()

(

long*pnumber=NULL;//Pointerdeclaration&initialization

longnumberl=55znumber2=99;

pnumber=&numberl;//Storeaddressinpointer

*pnumber+=11;//Incrementnumberlby11

cout<<endl

<<"numberl="<<numberl

<<"Snumberl=*'<<hex<<pnumber;

pnumber=&number2;//Changepointertoaddressofnumber2

numberl=*pnumber*10;//10timesnumber2

cout<<endl

<<"numberl="<<dec<<numberl

<<npnumber="<<hex<<pnumber

<<"*pnumber="<<dec<<*pnumber;

cout<<endl;

return0;

在筆者計(jì)算機(jī)上,木示例產(chǎn)生下面的輸出:

numberl=66&numberl=0012FEC8

numberl=990pnumber=0012FEBC?pnumber=99

示例說明

本示例沒有輸入,所有操作都是用變量的初值執(zhí)行的。將numberl的地址存入指針pnumber

之后,numberl的值通過下面這條語句中的指針而間接增加:

*pnumber+=11;//Incrementnumberlby11

注意:

當(dāng)首次聲明指針pnumber時(shí),我們將其初始化為NULL。我們將在下一小節(jié)討論指針初始

化■的問題。

間接運(yùn)算符使我們將pnumber所指變量即numberl的內(nèi)容加上11。如果忘記在這

條語句中寫上*號,則計(jì)算機(jī)將使該指針存儲的地址加上11。

numberl的值以及存儲在pnumber中的numberl的地址都被顯示出來。程序使用hex操作

148

第4章數(shù)組、字符串和指針

符,以生成十六進(jìn)制形式的地址輸出。

通過使用hex操作符,我們可以使普通整型變量的值也以十六進(jìn)制的形式輸出。只要我們

以與發(fā)送endl完全相同的方式將hex發(fā)送到輸出流中,則所有后面跟著的輸出就都是十六進(jìn)制。

如果我們希望后面的輸出再變?yōu)槭M(jìn)制,則需要在下?條輸出語句中使用dec操作符,將輸出

再次切換回十進(jìn)制模式。

在第,?行輸出之后,pnumber的內(nèi)容被設(shè)置為number2的地址。變量numberl的值則變?yōu)?/p>

number2的10倍:

numberl=*pnumber*10;//10timesnumber2

計(jì)算是借助于指針通過間接訪問number2的內(nèi)容進(jìn)行的。第二行輸出顯示出計(jì)算的結(jié)果。

您在輸出中看到的地址值可能與上面的示例輸出完全不同,因?yàn)檫@些值反映的是內(nèi)存中加

載該程序的位置,這取決于操作系統(tǒng)的配置情況。地址值的前綴Ox表明它們是十六進(jìn)制數(shù)。

注意,地址&numberl和pnum

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論