C++primer-3TH詳細(xì)答案打印版_第1頁
C++primer-3TH詳細(xì)答案打印版_第2頁
C++primer-3TH詳細(xì)答案打印版_第3頁
C++primer-3TH詳細(xì)答案打印版_第4頁
C++primer-3TH詳細(xì)答案打印版_第5頁
已閱讀5頁,還剩216頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡(jiǎn)介

練習(xí)2.16語言不應(yīng)該支持所謂的Type-constraint(類型約束)語法。有三個(gè)理由:

它會(huì)使templates更復(fù)雜。

無論如何用戶總是能夠檢驗(yàn)Type是否提供了“得以順利將此template實(shí)例化”的必要函數(shù);

如果他們遺漏了,編譯器會(huì)對(duì)此實(shí)例化行為發(fā)出錯(cuò)誤訊息,指出某個(gè)函數(shù)有所謂的隱式約束

(implicitconstraint),而不只是發(fā)出錯(cuò)誤信息說這個(gè)template的實(shí)例化是錯(cuò)誤的。

請(qǐng)看L&L練習(xí)2.16出現(xiàn)的腳注,其中所描述的習(xí)慣。

練習(xí)2.17這是正確的語意。另一種做法是在classtemplate被產(chǎn)生出來時(shí)即檢驗(yàn)此一template的所有可能

用法。這會(huì)造成編譯時(shí)間的嚴(yán)重浪費(fèi)。不過此種語意的缺點(diǎn)是,以某個(gè)類型將template實(shí)例化,在程

序A中也許可以有效運(yùn)作,在程序B中也許不能成功,視被調(diào)用的函數(shù)而定。

練習(xí)2.18以下事情有可能在這個(gè)函數(shù)中出現(xiàn)錯(cuò)誤:

file_name可能是個(gè)空字符串(emptystring)0

ifstreamconstructor可能無法打開文件,即使file_name是一個(gè)有效字符串。

文件起始處可能并不內(nèi)含一個(gè)int數(shù)值。

elem_cnt可能收到一個(gè)不正確的值:太大、或0、或負(fù)值。

allocate_array()為elem_cnt個(gè)元素分配空間,可能失敗。

while循環(huán)讀到太多元素;這個(gè)循環(huán)會(huì)在遇到EOF(或讀取int失敗)時(shí)結(jié)束,但它并未考慮pi

所指數(shù)組的大小。

sort__array()會(huì)對(duì)pi所指向的數(shù)組排序,該數(shù)組假想有elem_cnt個(gè)元素。但是while循

環(huán)可能在讀入elem_cnt個(gè)元素之前就結(jié)束,因?yàn)檩斎攵说膇nts個(gè)數(shù)不足,并因而造成數(shù)組的

剩余部分沒有初值。

sort_array()可能會(huì)收到一個(gè)無效指針pi,因?yàn)榇颂幉⑽礄z查allocate_array()的返回值:

這個(gè)錯(cuò)誤可能會(huì)造成程序在循環(huán)內(nèi)當(dāng)?shù)簟?/p>

練習(xí)2.19int*alloc_and_init(stringfile_name)

(

ifstreaminfile(file_name.c_str());

intelem_cnt;

infile>>elem_cnt;

try(

int*pi=allocate_array(elem_cnt);

intelem;

intindex=0;

while(cin>>elem)

pi[index++]=elem;

sort_array(pi,elem_cnt);

register_data(pi);

returnpi;

)

catch(constnoMem&n){

cout<<nallocate_array()error"<<n<<endl;

}

catch(inti){

cout<<nsort_array()error"<<i<<endl;

)

catch(conststring&s){

cout<<nregister_data()error'*<<s<<endl;

)

)

練習(xí)2.20int*alloc_and_init(stringfile_name)

(

try(

ifstreaminfile(file_name.c_str());

if(Jinfile)

throw"cannotopenfileH;

intelem_cnt;

infile>>elem_cnt;

if(!infileIIelem_cnt<=0)

throw"invalidelem_cntH;

int*pi=allocate_array(elem_cnt);

intelem;

intindex=0;

while(cin>>elem){

if(index>=elem_cnt)

throw"toomanyinputelements";

pi[index++]=elem;

}

sort_array(pi,index);

register_data(pi);

returnpi;

)

catch(constnoMem&n){

cout<<nallocate_array()errorn<<n<<endl;

throw;//重新丟出(rethrow)exception以便通知用戶

)

catch(inti){

cout<<nsort_array()errorn<<i<<endl;

throw;

)

catch(conststring&s){

cout<<nregister_data()error"<<s<<endl;

throw;

)

catch(constchar*s){

cout<<"error:“<<s<<endl;

throw;

)

)

練習(xí)2.21a.利用“前置修飾詞表示法”來訪問Exercisenamespace中的類型定義。

b.利用usingdeclaration來訪問類型定義。

c.利用namespace別名機(jī)制(aliasmechanism)。

d.利用usingdirectiveo

a.利用前置修飾詞表示法來訪問Exercisenamespace中的類型定義。

intmain()

(

//使用修飾詞表示法(*qualifiednamenotation*)

constintsize=1024;

Exercise::Array<Exercise::String>as(size);

Exercise::List<int>il(size);

//...

Exercise::Array<Exercise::String>*pas=

newExercise::Array<Exercise::String>(as);

Exercise::List<int>*pil=newExercise::List<int>(il);

Exercise::print(*pas);

}

b.利用usingdeclaration來訪問類型定義。

intmain()

(

//使用,usingdeclaration,

usingExercise::String;

usingExercise::Array;

usingExercise::print;

usingExercise::List;

constintsize=1024;

Array<String>as(size);

List<int>il(size);

〃…

Array<String>*pas=newArray<String>(as);

List<int>*pil=newList<int>(il);

print(*pas);

)

c.利用namespace的別名機(jī)制(aliasmechanism)。

intmain()

{

//使用namespacealias

namespaceE=Exercise;

練習(xí)2.22constintsize=1024;

E::Array<E::String>as(size);

E::List<int>il(size);

//...

E::Array<E::String>*pas=newE::Array<E::String>(as);

E::List<int>*pil=newE::List<int>(il);

E::print(*pas);

)

d.利用usingdirectiveo

intmain()

//使用,usingdirective'

usingnamespaceExercise;

constintsize=1024;

Array<String>as(size);

List<int>il(size);

//...

Array<String>*pas=newArray<String>(as);

List<int>*pil=newList<int>(il);

print(*pas);

)

練習(xí)2.22(a)vector<string>svecl(pals,pals+5);

svecl是一個(gè)由strings組成的vector,并以字符串所組成的數(shù)組pals作為初值。

(b)vector<int>ivecl(10);

ivecl是個(gè)vector,擁有10個(gè)ints,每一個(gè)都被初始化為0。

(c)vector<int>ivec2(10,10);

ivec2是一個(gè)vector,擁有10個(gè)ints,每一個(gè)都被初始化為10。

(d)vector<string>svec2(svecl);

svec2是一個(gè)vector,并以vectorsvecl作為初值。

(e)vector<double>dvec;

dvec是一個(gè)空的vector,內(nèi)部元素的類型是doubles。

練習(xí)2.23template<classelemType>

elemType

min(constvector<elemType>&vec);

下面是完整的程序:

#include<iostream>

#include<vector>

usingnamespacestd;

template<classelemType>

elemTypemini(constvector<elemType>&vec)

(

elemTypeminimum;

if(vec.size()>=1)

minimum=vec[0];

else

throw"Emptyvector-index";

for(inti=1;i<vec.size();i++)

if(vec[i]<minimum)

minimum=vec[i];

returnminimum;

)

練習(xí)2.23template<classelemType>

elemTypemin2(constvector<elemType>&vec)

vector<elemType>::const_iteratoriter=vec.begin();

elemTypeminimum;

if(iter<vec.end())

minimum=*iter;

else

throw"Emptyvector-iteratorn;

for(++iter;iter<vec.end();++iter)

if(*iter<minimum)

minimum=*iter;

returnminimum;

)

intmain()

intarray[]={9,4,5,6,1,3,7,8,2Z0};

vector<int>a(array,array+10);

cout<<"shouldbe0:n<<mini(a)<<endl;

cout<<"shouldbe0:n<<min2(a)<<endl;

vector<int>b(array,array+9);

cout<<"shouldbe1:“<<mini(b)<<endl;

cout<<"shouldbe1:“<<min2(b)<<endl;

vector<int>c;

try(

cout<<"shouldbel:n<<mini(c)<<endl;

cout<<"shouldbel:n<<min2(c)<<endl;

catch(char*s){

cerr<<"Exception:n<<s<<endl;

return0;

)

其中函數(shù)mini()和min2()十分類似,都使用for循環(huán),都在vector成空的時(shí)候丟出?個(gè)

exceptionomini()使用索引法:

for(inti=1;i<vec.size();i++)

if(vec[i]<minimum)

minimum=vec[i];

min2()使用iterator0兩者的參數(shù)都是?個(gè)constvector<elemType>&vec,所以我們不能使

用截至目前我們所見的?般性iterator。我們必須改用const_iterator(見L&L,12.4節(jié)):

for(++iter;iter<vec.end();++iter)

if(*iter<minimum)

minimum=*iter;

我們使用解引用(dereference)operator*來取用vector內(nèi)的數(shù)據(jù)。

主:程序以數(shù)組array作為vectora的初值:

intarray[]={9,4,5,6,1,3,7,8,2,0);

vector<int>a(array,array+10);

然后調(diào)用函數(shù)mini。和min2()?獲得的結(jié)果相同。我們也試了另一個(gè)vectorb,以數(shù)組的前九

個(gè)元素作為初值,并以一個(gè)空的vectorc練習(xí)exception處理機(jī)制。

練習(xí)3.1文字常量'a'表示單一字符a(類型為char。L,a'也表示單?字符a,但其類型為wchar_t,

因?yàn)榍皩?dǎo)詞L代表“寬字符”。

文字常量"a"和L"a"都是字符串,內(nèi)含單?一字符a和一個(gè)null字符(或是null寬字符)。

"a"的類型是“常量字符所形成的數(shù)組”,L"a"的類型則是“常量寬字符所形成的數(shù)組”。

(b)10,10u,10L,10uL,012,OxC

以上全都表示十進(jìn)制整數(shù)常量10。其中10,012和OxA的類型都是int,因?yàn)樗鼈儧]有任何修

飾詞。012的前導(dǎo)詞0表示這是個(gè)八進(jìn)位常量,OxA的前導(dǎo)詞Ox則表示它是一個(gè)十六進(jìn)制常量。

10u的類型是unsignedint)10L的類型是long,10uL的類型是unsignedlong。

(c)3.14,3.14f,3.14L

這些浮點(diǎn)數(shù)文字常量的類型都不相同。沒有任何修飾詞的3.14,類型為double(雙精度,這是

預(yù)設(shè)類型)。3.14f表現(xiàn)的是單精度浮點(diǎn)數(shù),3.14L表現(xiàn)的是多精度浮點(diǎn)數(shù)。

第3章

練習(xí)3.2(c)合法,但是其結(jié)果未有定義,因?yàn)椤皩蓚€(gè)不同類型的字符串連接起來,其行為未有定義”

(L&L,

p.78;簡(jiǎn)體版p.64)。

(e)和(f)不合法。3.14UL之所以不合法是因?yàn)閁(unsigned)被施加于?個(gè)浮點(diǎn)數(shù)文字常量身上。

(f)字符串需要在第一行最后加上一個(gè)倒斜線,才能延續(xù)到第二行:

(f)"multipleline\

comment"

另一種做法是把分據(jù)兩行的單一長(zhǎng)字符串寫為兩個(gè)字符串:

(f)"multipleline”

"comment

練習(xí)3.3(d)和(e)是不合法的。

(d)doublesalary=wage=9999.99;

此處wage被使用之前未曾先定義過。修正做法之一是把兩個(gè)變量分開定義、設(shè)初值,像這樣:

doublesalary=9999.99,wage=9999.99;

(e)cin>>intinput_value;

使用cin時(shí)并不允許“同時(shí)定義變量”。正確的做法是先定義好變量,再將?個(gè)值讀入變量之中:

intinput_value;

cin>>input_value;

練習(xí)3.4所謂lvalue(左值),是變量的地址,或是某個(gè)“代表對(duì)象在內(nèi)存中的位置”的表達(dá)式。所謂rvalue

(右值),就是變量的值。見L&L,3.2.1節(jié)。

變量名稱如果出現(xiàn)在賦值(assignment)運(yùn)算符的左側(cè),它就是一個(gè)lvalue。變量名稱或文字常

量如果出現(xiàn)于賦值(assignment)運(yùn)算符的右側(cè),它就是?個(gè)rvalue。例如:

ivar=val+2;

此處的ivar是個(gè)lvalue,val和2都是rvalueso

練習(xí)3.5(a)externstringname;

stringname("exercise3.5a");

第一個(gè)句子,externstringname;是name的聲明,告訴編譯器說,name所代表的對(duì)象,其

類型為string。此行并未分配內(nèi)存。

第二個(gè)句子,stringname("exercise3.5a");是個(gè)定義,告訴編譯器說,name所代表的對(duì)

象的類型為string,并進(jìn)行內(nèi)存分配操作,同時(shí)設(shè)好初值。

(b)externvector<string>students;

vector<string>students;

第一個(gè)句子是students的聲明,告訴編譯器說其類型為,?個(gè)“由strings組成的vector”。

沒有分配任何內(nèi)存。

第二個(gè)句子是個(gè)定義,告訴編譯器說,students所代表的對(duì)象類型為“由strings組成的

vectorMo此行將分配內(nèi)存,并以vector的defaultconstructor進(jìn)行初值設(shè)定工作。string的

defaultconstructor不會(huì)被調(diào)用,因?yàn)関ector是空的。

練習(xí)3.6(a),(c),(d)和(e)無效。

(a)和(c)之所以無效,因?yàn)樗鼈兤髨D使用保留字。double和namespace都是保留字(關(guān)鍵字)。

(d)內(nèi)含一個(gè)無效的符號(hào),(e)的名稱以數(shù)字開頭。

以卜是修訂后的結(jié)果:

(a)doublepi=3.14159;

(c)stringnamespace_string;

(d)stringcatch_22;

(e)charone_or_two=11';

(e)char_l_or_2=*1*;//另一種做法

練習(xí)3.7兩個(gè)string對(duì)象都將藉由stringclass的defaultconstructor加以初始化。

global_int會(huì)被初始化為0,而不會(huì)被初始化(所以其初值可能是任意數(shù)值)。

Global(全局)變量和對(duì)象可被其它函數(shù)訪問:local(局部)變量和對(duì)象只在它們定義所在的塊

內(nèi)可見。見L&L,3.2.3節(jié)。

練習(xí)3.8

33

練習(xí)3.8該語句有誤,因?yàn)樗髨D將?個(gè)int*數(shù)值賦值給一個(gè)int對(duì)象。另?個(gè)錯(cuò)誤:pi3是個(gè)“指

針的指針”,其值為0,而解引用null指針會(huì)造成運(yùn)行時(shí)刻錯(cuò)誤。

(b)*pi2=*pi3;

該語句也有一個(gè)錯(cuò)誤,理由與(a)相同。

(c)ival=pi2;

道理相同,企圖將一個(gè)int*數(shù)值賦值給一個(gè)int對(duì)象,是錯(cuò)誤的行為。

(d)pi2=*pil;

該語句有誤,因?yàn)樗鼘?個(gè)int數(shù)值賦值給個(gè)int*對(duì)象。

(e)pil=*pi3;

此處pil被賦值為pi3所指內(nèi)容。這個(gè)操作是合法的。如果pi3并未指向一個(gè)有效地址,該

行會(huì)發(fā)生運(yùn)行時(shí)刻錯(cuò)誤,但行為不可預(yù)期。

(f)ival=*pil;

由于(e)會(huì)在運(yùn)行時(shí)刻失敗,所以pil未被適當(dāng)?shù)爻跏蓟?。?duì)一個(gè)未被正確初始化的指針進(jìn)行

解引用操作,會(huì)發(fā)生錯(cuò)誤。

如果此行之前的那些定義都成立,那么此行會(huì)將ival賦值給ival。這是因?yàn)閜il被初始化為

ival的地址,所以解引用pil會(huì)獲得ival的值,此值再被賦值給ival。

(g)pil=ival;

此行錯(cuò)誤,因?yàn)閜il的類型是int*,而ival的類型是int。

(h)pi3=&pi2;

此行正確,因?yàn)閜i3的類型是int**,而pi2的類型是int*,因此&pi2的類型也是int**。

練習(xí)3.9

上述第二行將指針pi前進(jìn)1,024個(gè)位置。如果pi是個(gè)int指針,那么在“int為32位”

的環(huán)境下就是前進(jìn)了4096個(gè)字節(jié)。如果pi最初指向一個(gè)有著適當(dāng)大小的數(shù)組(亦即ival2代表

該數(shù)組內(nèi)的某元素),那么這就不見得是個(gè)錯(cuò)誤。

練習(xí)3.10問題在于Pi2定義時(shí)并未指向一塊已獲分配的空間,而foobar()卻企圖對(duì)其參數(shù)所指的內(nèi)存

做寫入操作。本例中的pi2初值為0,所以foobar()試圖將1024寫入地址為0的內(nèi)存中。除非

指針被賦以?個(gè)實(shí)際值,否則運(yùn)行時(shí)刻的行為沒有定義。下面是修改方式之一:

intfoobar(int*pi){

if(pi){

*pi=1024;

return*pi;

練習(xí)3.11

35

}else{

return0;

}

}

intmain()

{

intival2=0;

intival=foobar(&ival2);

return0;

)

這次我們不再定義一個(gè)int指針,而是定義?個(gè)int對(duì)象ival2,并將其地址傳給foobar()。

問題真正的解決點(diǎn)是在foobar()中對(duì)pi的測(cè)試操作。任何人如果事先不知道指針是否有值,都應(yīng)

該先行測(cè)試,然后才對(duì)指針做操作。

練習(xí)3.11由于指針扮演如此突顯的角色,執(zhí)行時(shí)期的任何指針檢驗(yàn)操作都會(huì)導(dǎo)致不可接受的效率成本。編

譯時(shí)期的指針檢驗(yàn)工作很困難,因?yàn)橥鶡o法決定這些指針在執(zhí)行時(shí)期會(huì)有什么值。

程序員之間流傳著指針的某些使用準(zhǔn)則,包括:總是將指針初始化、不要無視編譯器發(fā)出的錯(cuò)誤

信息或警告信息如“強(qiáng)制轉(zhuǎn)換為指針變量(explicitcaststopointervariables)”等等。

練習(xí)3.12(a)charch="Thelong,windingroad";

這是錯(cuò)誤的,因?yàn)閏h是單個(gè)字符,卻被初始化為一個(gè)字符串。

(b)intival=&ch;

(c)char*pc=&ival;

以上兩行都不正確,因?yàn)樗鼈兤髨D以不兼容的數(shù)值作為變量的初值:把char*交給int,把int

*交給char*o

(d)stringst(&ch);

語法上正確。但是如果ch未被正確地初始化,st可能會(huì)有不如預(yù)期的結(jié)果。另一個(gè)重點(diǎn)是,

string(constchar*)constructor期望獲得一個(gè)以null為結(jié)束符號(hào)的char數(shù)組。

(e)pc=0;

正確。

(f)st=pc;

語法正確。執(zhí)行結(jié)果視pc的值而定。

(9)ch=pc[0];

語法正確。執(zhí)行結(jié)果視pc的值而定。

(h)pc=st;

(i)pc=*0*;

以上兩行都不正確,因?yàn)闆]有任何隱式轉(zhuǎn)換可以將string或constchar轉(zhuǎn)換為char

(j)st=&ival;

這一行也不正確,因?yàn)闆]有任何可接受的轉(zhuǎn)換行為可以將int*轉(zhuǎn)換為stringo

(k)ch=*pc;

語法正確。執(zhí)行結(jié)果視pc的值而定。

(1)*pc=ival;

以上操作將一個(gè)int數(shù)值賦值給一個(gè)char??赡軙?huì)發(fā)生上溢(overflow)情況。執(zhí)行結(jié)果視ival

和pc的值而定。

練習(xí)3.13第一個(gè)while循環(huán)會(huì)持續(xù)累加ent,直到st的值為0。如果st并不是從0開始起算,那么

循環(huán)會(huì)一直進(jìn)行,直到st的值爆掉(超過st的容量)為止。

第二個(gè)while循環(huán)會(huì)累加ent,直到st所指的值為0。如果st指向一個(gè)C-style字符串,

那么循環(huán)會(huì)持續(xù)進(jìn)行,直到字符串的尾端為止。

練習(xí)3.14這些程序都進(jìn)行1,000,000次循環(huán),循環(huán)內(nèi)對(duì)字符串做內(nèi)存分配、復(fù)制、比較、內(nèi)存釋放操作。

一開始,有一個(gè)基本字符串在循環(huán)之外獲得初值。循環(huán)之內(nèi)則決定基本字符串的長(zhǎng)度。在C-style版

本內(nèi),這長(zhǎng)度值用來分配?個(gè)新的char數(shù)組,并將基本字符串復(fù)制到該數(shù)組。class版本內(nèi)則定義

一個(gè)新字符串并以基本字符串作為初值。接下來基本字符串被拿來和新字符串比較,如有差異就將錯(cuò)

誤計(jì)數(shù)器加lo最后,C-style版明白釋放新字符串的空間,class版則依賴classdestructor完成內(nèi)存

釋放操作。

class版所花時(shí)間比較少,主要原因是字符串長(zhǎng)度系儲(chǔ)存于stringclass內(nèi),成為其成員之一。

當(dāng)C-style版調(diào)用strlen時(shí),整個(gè)字符串必須被走過一遍,才能知道其長(zhǎng)度。注意,在我的系統(tǒng)中,

class版比C-style版慢。某些系統(tǒng)在string身上使用referencecounting(引用計(jì)數(shù))技巧,那么就

會(huì)比較快。(譯注:關(guān)于“引用計(jì)數(shù)”技巧,可參考More助認(rèn)C++(ScottMeyers著,侯捷譯,

培生2000)的條款29)。

練習(xí)3.15加上某些可作用于子字符串身上的額外操作,可能會(huì)有益處。例如在一個(gè)字符串中搜尋子字符串,

以及對(duì)子字符串進(jìn)行替換、復(fù)制、比較或串接等操作。

其它有益的操作還包括大小寫轉(zhuǎn)換、文字轉(zhuǎn)為整數(shù)(atoiO)>文字轉(zhuǎn)為浮點(diǎn)數(shù)(atof())等等。

練習(xí)3.16?個(gè)可被修改的對(duì)象,類型為int。

(b)constintic;

一個(gè)固定不變(不可修改)的對(duì)象,類型為int。

(c)constint*pic;

pic是個(gè)指針,指向一個(gè)類型為int的常量對(duì)象。pic本身可被修改,但是它所指的對(duì)象內(nèi)容

不可修改。

(d)int*constcpi;

cpi是常量指針,指向?個(gè)類型為int的對(duì)象。cpi不可修改,但其所指對(duì)象可以修改。

(e)constint*constepic;

epic是常量指針,指向一個(gè)類型為int的常量對(duì)象。不論epic或是其所指對(duì)象都不可以修改。

(b),(d),和<e)都是不合法的定義,因?yàn)槌A繉?duì)象必須有初值。任何人如果企圖修改常量對(duì)象,

會(huì)引發(fā)錯(cuò)誤信息。

練習(xí)3.17合法。i不是常量,初值設(shè)定為-1。

(b)constintic=i;

合法。ic是常量,初值設(shè)定為i。之后無法修改其值。

(c)constint*pic=⁣

合法。pic是個(gè)指針,指向一個(gè)類型為int的常量對(duì)象。pic可被修改,但其所指對(duì)象是常量。

由于ic已有定義,所以上述初始化行為是合法的。

(d)int*constcpi=⁣

不合法。cpi是一個(gè)常量指針,指向int,但ic卻是個(gè)constinto

(e)constint*constepic=⁣

合法。此處epic是一個(gè)常量指針,指向constint,ic的類型也是constinto不論是epic

或其所指對(duì)象ic,都無法修改。

練習(xí)3.18(a)i=ic;

合法。i不是常量,所以可以被修改。

(b)pic=⁣

合法。pic不是常量,所以它可以被修改,不過它所指的對(duì)象的類型必須是constinto

(c)cpi=pic;

不合法。cpi是常量,所以它不可以被修改。

(d)pic=epic;

合法。pic不是常量,所以它可以被修改,但是它所指的對(duì)象的類型必須是constinto

(e)epic=⁣

不合法。epic是常量,所以不能被修改。

(f)ic=*cpic;

不合法。ic是常量,所以不能被修改。

練習(xí)3.19(b)intSrvall=1.01;

無效。能夠儲(chǔ)存文字常量者,必須是一個(gè)constreference0可修改如下:

constint&rvall=1.01;

(d)int&rval3=&ival;

無效。rval3的類型是int而非int★<,可修改如下:

int&rval3=ival;

int*const&rva13=Sival;

(f)int&rval4=pi;

無效。rval4的類型是int而非int可修改如下:

int*const&rval4=pi;

(h)int&*prvall=pi;

無效。一個(gè)“指向reference”的指針是不合法的??尚薷娜缦拢?/p>

int*&prvall=pi;

(j)constint&*prval2=&ival;

無效。?個(gè)“指向referencen的指針是不合法的??尚薷娜缦拢?/p>

int*const&prval2=&ival;

練習(xí)3.20(a)rvall=3.14159;

無效,因?yàn)槲淖殖A啃枰粋€(gè)constreference來容納。

(b)prvall=prval2;

無效,因?yàn)閜rvall和prva12都是“指向reference”的指針,而那是不合法的。

(c)prval2=rvall;

無效,因?yàn)閜rval2是?個(gè)“指向reference"的指針,而那是不合法的。

(d)*prval2=ival2;

無效,因?yàn)閜rval2是一個(gè)“指向reference的指針,而那是不合法的。

練習(xí)3.21第一個(gè)語句正確:它將ival的地址設(shè)給指針pi。

第二個(gè)語句錯(cuò)誤,因?yàn)槲覀儫o法將int*(ival的地址)轉(zhuǎn)換為constint(referenceri的

類型是constint)o

最后一個(gè)語句錯(cuò)誤,因?yàn)閞val未曾定義。

練習(xí)3.22(a)intia[buf_size];

不合法,因?yàn)閎uf_size不是一個(gè)常量。

(b)intia[get_size()];

不合法,因?yàn)間et_size()不是一個(gè)常量表達(dá)式。

(d)intia[2*7-14];

不合法,因?yàn)榉峙浯笮?的數(shù)組是錯(cuò)誤的行為。

(e)charst[11]=nfundamentaln;

不合法。沒有足夠的空間來放置字符串初值。應(yīng)該再多一個(gè)元素,用來放置字符串尾端的字

符。

練習(xí)3.23數(shù)組的索引從0開始。因此,ia的元素索引為0~9。但是for循環(huán)內(nèi)的索引碼卻是下

面是修改后的版本:

intmain(){

constintarray_size=10;

intia[array_size];

for(intix=0;i<array_size;++ix)

ia[ix]=ix;

//...

)

練習(xí)3.24(a)vector<vector<int>>ivec;

正確。

(b)vector<int>ivec={0,1,1,2,3,5,8};

不正確。這種初始化形式無法用于vector對(duì)象身上。

(c)vector<int>ivec(ia,ia+7);

正確。

(d)vector<string>svec=ivec;

不正確?!癷nt所組成的vector"無法轉(zhuǎn)換為“string所組成的vector"。

(e)vector<string>svec(10,string("nulln));

正確。

練習(xí)3.25boolis_equal(constint*ia,intia_sizezconstvector<int>&ivec)

inti=0;

for(vector<int>::const_iteratorit=ivec.begin();

it!=ivec.end();++it){

//如果到達(dá)數(shù)組尾端,不要再繼續(xù)前進(jìn)

if(i==ia_size)

break;

〃如果發(fā)現(xiàn)?個(gè)不同值,立刻返回

if(ia[i++]!=*it)

returnfalse;

}

returntrue;

)

下面是測(cè)試程序。

intmain()

constintasize=7;

intia6eq[6]=0,1,1,2,3,5};

intia6ne[6]=0z1,1,3,3Z5};

intia8eq[8]=0,1,1,2,3,5,8,13);

intia8ne[8]=0,lr1,2,3,5,9,13);

intiane[asize]1/1,1,2,3,5,8};

intia[asize]0,1,1,2,3,5,8);

vector<int>ivec(ia,ia+asize);

cout<<nis_equal(ia6eq,6,ivec):";

if(is_equal(ia6eq,6,ivec))

cout<<"equal\nn;

else

cout<<"notequal\nn;

cout<<nis_equal(ia6ne,6,ivec):**;

if(is_equal(ia6ne,6,ivec))

cout<<"equal\nn;

else

cout<<nnotequal\nn;

nH

cout<<is_equal(ia8eqz8,ivec):;

if(is_equal(ia8eq,8,ivec))

cout<<"equal\nn;

else

cout<<"notequal\nn;

cout<<nis_equal(ia8ne,8,ivec):H;

if(is_equal(ia8ne,8,ivec))

cout<<"equal\n*';

else

cout<<"notequal\n*';

cout<<"is_equal(ia,asize,ivec):n;

if(is_equal(ia,asize,ivec))

cout<<"equal\n*';

else

cout<<"notequal\nn;

cout<<nis_equal(iane,asize,ivec):n;

if(is_equal(iane,asize,ivec))

cout<<"equal\nH;

else

cout<<nnotequal\nH;

return0;

)

練習(xí)3.26我們知道那些重復(fù)的代碼涉及_size和.string的初始化行為。我將這些代碼抽取出來放進(jìn)

兩個(gè)privateoverloadedmemberfunctionsinit(),并在constructorsassignmentoperators內(nèi)的適

步地點(diǎn)放置適當(dāng)?shù)暮瘮?shù)調(diào)用。

首先,在Stringclass的private區(qū)段內(nèi)為新函數(shù)加上聲明:

private:

int_size;

char*_string;

voidinit(constchar*);

voidinit(constStrings);

共同的初始化程序代碼現(xiàn)在被我放進(jìn)兩個(gè)新函數(shù)內(nèi):

inlinevoid

String::init(constchar*s)

(

if(!s){

_size=0;

_string=0;

}else{

_size=strlen(s);

_string=newchar[__size+l];

strcpy(_string,s);

)

)

inlinevoid

String::init(constString&rhs)

{

_size=rhs._size;

if(!rhs._string)

_string=0;

else{

_string=newchar[_size+l];

strcpy(_stringzrhs,_string);

)

)

接下來更改constructors,以便調(diào)用initU):

inlineString::String()

(

init(0);

)

inlineString::String(constchar*s)

init(s);

}

inlineString::String(constString&rhs)

init(rhs);

)

assignmentoperators的修改方式極為類似:

inlineString&

String::operator=(constchar*s)

delete[]_string;

init(s);

return*this;

inlineStrings

String::operator=(constString&rhs)

if(this!=&rhs){

delete[]_string;

init(rhs);

return*this;

}

練習(xí)3.27修改方式非常直接易懂。首先為新字母加上對(duì)應(yīng)的計(jì)數(shù)器:

bCnt=0,dCnt=0,fCnt=0,sCnt=0,tCnt=0

接下來在switch語句中為這些輔音加上新的cases。我們還是需要為每?個(gè)輔音累加

notVowel的值。

case1b:caseB*:++bCnt;++notVowel;break;

case*d:caseD*:++dCnt;++notVowel;break;

case*f:caseF1:++fCnt;++notVowel;break;

case1s:caseS*:++sCnt;++notVowel;break;

case1t:caseT*:++tCnt;++notVowel;break;

最后,修改輸出部分以顯示輔音個(gè)數(shù)。下面是整個(gè)程序。

#include*'string.h

intmain()

intaCnt=0,eCnt=0ziCnt=0,oCnt=0,uCnt=0,

bCnt-0,dCnt=0,fCnt=0,sCnt=0,tCnt=0,

theCnt=0,itCnt=0,wdCnt=0,notVowel=0;

nn

Stringbuf,the(the)zit;

while(cin>>buf){

++wdCnt;

cout<<buf<<

if(wdCnt%12==0)

cout<<endl;

if(bufthe||buf“The”)

++theCnt;

elseif(bufitIIbufnItn)

++itCnt;

for(intix=0;i<buf.size();++ix){

switch(buf[ix]){

caseacaseA:++aCnt;break;

caseecaseE:++eCnt;break;

case1icaseI:++iCnt;break;

casecase0:++oCnt;break;

caseucaseU:++uCnt;break;

case*bcaseB:++bCnt;++notVowel;break;

case,dcaseD:++dCnt;++notVowel;break;

casecaseF:++fCnt;++notVowel;break;

casecaseS:++sCnt;++notVowel;break;

casecaseT:++tCnt;++notVowel;break;

default:++notVowel;break;

cout<<

<<Wordsread:“<<wdCnt<<

<<the/The:u<<theCnt<<n\n

<<it/It:"<<itCnt<<n\n\n

<<non-vowelsread:n<<notVowel<<*'\n

<<<<aCnt<<M\n

<<<<eCnt<<M\n

<<<<iCnt

<<o<<oCnt

<<u<<uCnt<<"\n\n

<<b<<bCnt

<<d<<dCnt?H\n

<<<<fCnt

<<<<sCnt

<<t<<tCnt<<endl;

return0;

練習(xí)3.28下面是其實(shí)現(xiàn)代碼:

inlineint

String::count(charch)const

intchCnt=0;

for(intix=0;i<_size;++ix)

if(_string[ix]ch)++chCnt;

returnchCnt;

我必須修改原先的程序以測(cè)試這一新函數(shù)。對(duì)于計(jì)算元音個(gè)數(shù)而言,這是非常缺乏效率的做法,

但這使我們得以拿兩種做法互相比較。

#include"string.h"

intmain()

(

intaCnt=0,eCnt=0,iCnt=0,oCnt=0,uCnt=0,

theCnt=0,itCnt=0,wdCnt=0;

Stringbuf,the("the"),it(nit");

while(cin>>buf){

++wdCnt;

cout<<buf<<**;

if(wdCnt%12==0)

cout<<endl;

if(buf==the||buf=="The")

++theCnt;

elseif(buf==itIIbuf==n11")

++itCnt;

aCnt+=buf.count(*a1);

aCnt+=buf.count(*A1);

eCnt+=buf.count(re');

eCnt+=buf.count(*E');

iCnt+=buf.count(Ti');

iCnt+=buf.count(*1');

oCnt+=buf.count(*o');

oCnt+=buf.count(*0,);

uCnt+=buf.count(1u');

uCnt+=buf.count(1U1);

)

cout<<n\n\n”

<<Wordsread:'*<<wdCnt<<*'\n\n

<<the/The:n?theCnt?”\n”

<<it/It:"<<itCnt<<n\n\n

<<a<<aCnt<<n\n"

<<<<eCnt?“\n”

<<i<<iCnt<<'*\nn

<<o<<oCnt?H\n

<<u<<uCnt<<endl;

return0;

)

練習(xí)3.29卜面是我們的新函數(shù):

inlineString

String::operator+(constString&rhs)const

StringnewString;

if(!rhs._string)

newString=*this;

elseif(!_string)

newString=rhs;

else{

newString._size=_size+rhs._size;

newString._string=newchar[newString._size+1];

strcpy(newString._string,_string);

strcat(newString._string,rhs._string);

)

returnnewString;

}

我們首先檢查是否有任何一個(gè)字符串是空字符串。如果有,就返回非空字符串的一份副本。如果

兩者都是空字符串,則返回其中一個(gè)空字符串的新副本。

如果兩個(gè)操作數(shù)都不是空字符串,我們就計(jì)算新的大小:

newString._size=_size+rhs._size;

并分配內(nèi)存給新字符串使用:

newString._string=newchar[newString._size+1];

利用c標(biāo)準(zhǔn)程序庫所提供的函數(shù),我們復(fù)制第一個(gè)字符串:

strcpy(newString._string,_string);

然后為它接上第二個(gè)字符串:

strcat(newString._string,rhs._string);

最后,返回新字符串。

下面是一個(gè)小型測(cè)試程序。

#include“string"

intmain()

{

Stringempty;

Stringstrl(nThecow

Stringstr2("jumpedoverthemoon.");

Stringstr3=strl+str2;

cout<<"String1:|n<<strl<<

cout<<"String2:|n<<str2<<

//測(cè)試空字符串的連接

str3-str3+empty;

str3=empty+str3;

cout<<"String1+String2:|n<<str3<<H!\nn;

return0;

)

練習(xí)4.1表達(dá)式:

dvall/dval

溫馨提示

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

最新文檔

評(píng)論

0/150

提交評(píng)論