程序員面試分類模擬1_第1頁(yè)
程序員面試分類模擬1_第2頁(yè)
程序員面試分類模擬1_第3頁(yè)
程序員面試分類模擬1_第4頁(yè)
程序員面試分類模擬1_第5頁(yè)
已閱讀5頁(yè),還剩28頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡(jiǎn)介

程序員面試分類模擬1論述題1.

static(靜態(tài))變量有什么作用正確答案:在C語(yǔ)言中,關(guān)鍵字static的意思是靜態(tài),它有3個(gè)明顯的作用:

1)在函數(shù)體內(nèi),靜態(tài)變量具有“記憶”功能,即一個(gè)(江南博哥)被聲明為靜態(tài)的變量在這一函數(shù)被調(diào)用的過(guò)程中其值維持不變。

2)在模塊內(nèi)(但在函數(shù)體外),它的作用域范圍是有限制的,即如果一個(gè)變量被聲明為靜態(tài)的,那么該變量可以被模塊內(nèi)所有函數(shù)訪問(wèn),但不能被模塊外其他函數(shù)訪問(wèn)。它是一個(gè)本地的全局變量,如果一個(gè)函數(shù)被聲明為靜態(tài)的,那么該函數(shù)與普通函數(shù)作用域不同,其作用域僅在本文件中,它只可被這一模塊內(nèi)的其他函數(shù)調(diào)用,不能被模塊外的其他函數(shù)調(diào)用,也就是說(shuō)這個(gè)函數(shù)被限制在聲明它的模塊的本地范圍內(nèi)使用。

3)內(nèi)部函數(shù)應(yīng)該在當(dāng)前源文件中說(shuō)明和定義,對(duì)于可在當(dāng)前源文件以外使用的函數(shù),應(yīng)該在一個(gè)頭文件中說(shuō)明,使用這些函數(shù)的源文件要包含這個(gè)頭文件。

具體而言,static全局變量和普通的全局變量的區(qū)別在于static全局變量只初始化一次,這樣做的目的是為了防止在其他文件單元中被引用。static局部變量和普通局部變量的區(qū)別在于static局部變量只被初始化一次,下一次的運(yùn)算依據(jù)是上一次的結(jié)果值。static()函數(shù)與普通函數(shù)的區(qū)別在于作用域不一樣,static()函數(shù)只在一個(gè)源文件中有效,不能被其他源文件使用。

C++中,在類內(nèi)數(shù)據(jù)成員的聲明前加上關(guān)鍵字static,該數(shù)據(jù)成員就是類內(nèi)的靜態(tài)數(shù)據(jù)成員。靜態(tài)數(shù)據(jù)成員有以下特點(diǎn):

1)對(duì)于非靜態(tài)數(shù)據(jù)成員,每個(gè)類對(duì)象都有自己的復(fù)制品。而靜態(tài)數(shù)據(jù)成員被當(dāng)做是類的成員。無(wú)論這個(gè)類的對(duì)象被定義了多少個(gè),靜態(tài)數(shù)據(jù)成員在程序中也只有一份復(fù)制品,由該類型的所有對(duì)象共享訪問(wèn)。

2)靜態(tài)數(shù)據(jù)成員存儲(chǔ)在全局?jǐn)?shù)據(jù)區(qū)。定義時(shí)要分配空間,所以不能在類聲明中定義。由于靜態(tài)數(shù)據(jù)成員屬于本類的所有對(duì)象共享,所以它不屬于特定的類對(duì)象,在沒(méi)有產(chǎn)生類對(duì)象時(shí)其作用域就可見(jiàn),即在沒(méi)有產(chǎn)生類的實(shí)例時(shí),程序員也可以使用它。

3)靜態(tài)數(shù)據(jù)成員和普通數(shù)據(jù)成員一樣遵從public、protected、private訪問(wèn)規(guī)則。

4)static成員變量的初始化是在類外,此時(shí)不能再帶上static的關(guān)鍵字。private、protected的static成員雖然可以在類外初始化,但是不能在類外被訪問(wèn)。

與全局變量相比,使用靜態(tài)數(shù)據(jù)成員有以下兩個(gè)優(yōu)勢(shì):

1)靜態(tài)數(shù)據(jù)成員沒(méi)有進(jìn)入程序的全局名字空間,因此不存在與程序中其他全局名字沖突的可能性。

2)可以實(shí)現(xiàn)信息隱藏。靜態(tài)數(shù)據(jù)成員可以是private成員,而全局變量不能。

需要注意的是,類的靜態(tài)成員必須初始化,因?yàn)樗窃诔绦虺跏蓟臅r(shí)候分配的。類中只是聲明,在cpp中才是初始化,可以在初始化的代碼上放個(gè)斷點(diǎn),在程序執(zhí)行main()的第一條語(yǔ)句之前就會(huì)先走到那兒。如果靜態(tài)成員是個(gè)類,那么就會(huì)調(diào)用到它的構(gòu)造函數(shù)。

與靜態(tài)數(shù)據(jù)成員一樣,當(dāng)類的成員函數(shù)前面添加了static關(guān)鍵字后就變?yōu)榱祟惖撵o態(tài)成員函數(shù),靜態(tài)成員函數(shù)為類的全部服務(wù)而不是為某一個(gè)類的具體對(duì)象服務(wù)。靜態(tài)成員函數(shù)是類的內(nèi)部實(shí)現(xiàn),屬于類定義的一部分。普通的成員函數(shù)一般都隱含了一個(gè)this指針,this指針指向類的對(duì)象本身,因?yàn)槠胀ǔ蓡T函數(shù)總是具體的屬于某個(gè)類的具體對(duì)象的。通常情況下,this是默認(rèn)的。如函數(shù)fn()實(shí)際上是this->fn()。但是與普通函數(shù)相比,靜態(tài)成員函數(shù)由于不是與任何的對(duì)象相聯(lián)系,因此它不具有this指針。從這個(gè)意義上講,它無(wú)法訪問(wèn)屬于類對(duì)象的非靜態(tài)數(shù)據(jù)成員,也無(wú)法訪問(wèn)非靜態(tài)成員函數(shù),只能調(diào)用其余的靜態(tài)成員函數(shù)。

引申1:為什么static變量只初始化一次?

對(duì)于所有的對(duì)象(不僅僅是靜態(tài)對(duì)象),初始化都只有一次,而由于靜態(tài)變量具有“記憶”功能,初始化后,一直沒(méi)有被銷毀,而是保存在內(nèi)存區(qū)域中,所以不會(huì)再次初始化。

存放在靜態(tài)區(qū)的變量的生命周期一般比較長(zhǎng),一般與整個(gè)源程序“同生死、共存亡”,所以它只需初始化一次。而auto變量,即自動(dòng)變量,由于存放在棧區(qū),一旦調(diào)用過(guò)程結(jié)束,就會(huì)立刻被銷毀。

分析以下程序代碼:

#include<stdio.h>&

voidfun(inti)

{

staticintvalue=i++:

printf("%d\n",value);

}

intmain()

{

fun(0);

fun(1);

fun(2);

return0;

}

程序輸出為

0

0

0

程序每次輸出都為0,是因?yàn)関alue是靜態(tài)類型(static),只會(huì)定義一次。也就是說(shuō),不管調(diào)用fun()這個(gè)函數(shù)多少次,staticintvalue=i++這個(gè)定義語(yǔ)句只會(huì)在第一次調(diào)用的時(shí)候執(zhí)行,由于第一次執(zhí)行的時(shí)候i=0,所以value也就被初始化成0了,以后調(diào)用fun()都不會(huì)再執(zhí)行這條語(yǔ)句的。

分析以下一段代碼:

#include<stdio.h>

voidfun(inti)

{

staticintvalue=i++:

value=i++:

printf("%d\n",value);

}

intmain()

{

fun(0);

fun(1);

fun(2);

return0;

}

程序輸出為

1

1

2

上述代碼之所以輸出為1,1,2,是因?yàn)楫?dāng)調(diào)用fun(0)時(shí),由于value被聲明為static,所以定義語(yǔ)句只執(zhí)行一次,此時(shí)value=i++,value的值為0,i的值變?yōu)?,執(zhí)行第二行語(yǔ)句value=i++后,此時(shí)value的值為i的初值為1,接著i的值變?yōu)?,所以第一次輸出為1。當(dāng)調(diào)用fun(1)時(shí),因?yàn)関alue是靜態(tài)變量,具有記憶功能,所以會(huì)跳過(guò)定義語(yǔ)句,只執(zhí)行value=i++語(yǔ)句,所以value的值為1,而此時(shí)i的值變?yōu)?,所以第二次調(diào)用時(shí)輸出為1。當(dāng)調(diào)用fun(2)的時(shí)候,也會(huì)跳過(guò)定義語(yǔ)句,只執(zhí)行value=i++語(yǔ)句,所以value的值為2,i的值變?yōu)?,所以第三次調(diào)用時(shí)輸出為2。

引申2:在頭文件中定義靜態(tài)變量,是否可行?為什么?

不可行,如果在頭文件中定義靜態(tài)變量,會(huì)造成資源浪費(fèi)的問(wèn)題,同時(shí)也可能引起程序錯(cuò)誤。因?yàn)槿绻谑褂昧嗽擃^文件的每個(gè)C語(yǔ)言文件中定義靜態(tài)變量,按照編譯的步驟,在每個(gè)頭文件中都會(huì)單獨(dú)存在一個(gè)靜態(tài)變量,從而會(huì)引起空間浪費(fèi)或者程序錯(cuò)誤。

所以不推薦在頭文件中定義任何變量,當(dāng)然也包括靜態(tài)變量。

2.

const有哪些作用正確答案:常類型也稱為const類型,是指使用類型修飾符const說(shuō)明的類型。const是C和C++中常見(jiàn)的關(guān)鍵字,在C語(yǔ)言中,它主要用于定義變量為常類型以及修飾函數(shù)參數(shù)與返回值,而在C++中還可以修飾函數(shù)的定義,定義類的成員函數(shù)。常類型的變量或?qū)ο蟮闹凳遣荒鼙桓碌摹?/p>

一般而言,const有以下幾個(gè)方面的作用:

1)定義const常量,具有不可變性。例如:

constintMAX=100;

intArray[MAX];

2)進(jìn)行類型檢查,使編譯器對(duì)處理內(nèi)容有更多的了解,消除了一些隱患。例如:voidf(constinti){...}編譯器就會(huì)知道i是一個(gè)常量,不允許修改。

3)避免意義模糊的數(shù)字出現(xiàn),同樣可以很方便地進(jìn)行參數(shù)的調(diào)整和修改。同宏定義一樣,可以做到不變則已,一變都變。如1)中,如果想修改MAX的內(nèi)容,只需要定義constintMAX=期望值即可。

4)保護(hù)被修飾的東西,防止被意外的修改,增強(qiáng)了程序的健壯性。上例中,如果在函數(shù)體內(nèi)修改了變量i的值,那么編譯器就會(huì)報(bào)錯(cuò)。例如:

voidf(constinti)

{

i=10:

}

上述代碼對(duì)i賦值會(huì)導(dǎo)致編譯錯(cuò)誤。

5)為函數(shù)重載提供參考。

classA

{

voidf(inti){...}

∥定義一個(gè)函數(shù)

voidf(inti)const{...}

∥上一個(gè)函數(shù)的重載

}

6)節(jié)省空間,避免不必要的內(nèi)存分配。例如:

#definePI3.14159

∥該宏用來(lái)定義常量

constdoulbePi=3.14159;

∥此時(shí)并未將Pi放入只讀存儲(chǔ)器中

doublei=Pi;

∥此時(shí)為Pi分配內(nèi)存,以后不再分配

doubleI=PI;

∥編譯期間進(jìn)行宏替換,分配內(nèi)存

doublei=Pi;

∥沒(méi)有內(nèi)存分配

doubleJ=PI:

∥再次進(jìn)行宏替換,又一次分配內(nèi)存

const定義常量從匯編的角度來(lái)看,只是給出了對(duì)應(yīng)的內(nèi)存地址,而不是像#define一樣給出的是立即數(shù),所以const定義的常量在程序運(yùn)行過(guò)程中只有一份復(fù)制品,而#define定義的常量在內(nèi)存中有若干個(gè)復(fù)制品。

7)提高了程序的效率。編譯器通常不為普通const常量分配存儲(chǔ)空間,而是將它們保存在符號(hào)表中,這使得它成為一個(gè)編譯期間的常量,沒(méi)有了存儲(chǔ)與讀內(nèi)存的操作,使得它的效率也很高。

引申1:什么情況下需要使用const關(guān)鍵字?

1)修飾一般常量。一般常量是指簡(jiǎn)單類型的常量。這種常量在定義時(shí),修飾符const可以用在類型說(shuō)明符前,也可以用在類型說(shuō)明符后。

例如:intconstx=2或constintx=2。

2)修飾常數(shù)組。定義或說(shuō)明一個(gè)常數(shù)組可以采用如下格式:

intconsta[8]={1,2,3,4,5,6,7,8};

constinta[8]={1,2,3,4,5,6,7,8};

3)修飾常對(duì)象。常對(duì)象是指對(duì)象常量,定義格式如下:

classA;

constAa:

Aconsta:

定義常對(duì)象時(shí),同樣要進(jìn)行初始化,并且該對(duì)象不能再被更新,修飾符const可以放在類名后面,也可以放在類名前面。

4)修飾常指針。

constint*A:∥const修飾指向的對(duì)象,A可變,A指向的對(duì)象不可變

intconst*A:∥const修飾指向的對(duì)象,A可變,A指向的對(duì)象不可變

int*constA:∥const修飾指針A,A不可變,A指向的對(duì)象可變

constint*constA;∥指針A和A指向的對(duì)象都不可變

5)修飾常引用。使用const修飾符也可以說(shuō)明引用,被說(shuō)明的引用為常引用,該引用所引用的對(duì)象不能被更新。其定義格式如下:

constdouble&v;

6)修飾函數(shù)的常參數(shù)。const修飾符也可以修飾函數(shù)的傳遞參數(shù),格式如下:

voidFun(constintVar);

告訴編譯器var在函數(shù)體中的無(wú)法改變,從而防止了使用者一些無(wú)意的或錯(cuò)誤的修改。

7)修飾函數(shù)的返回值。const修飾符也可以修飾函數(shù)的返回值,返回值不可被改變,格式如下:

constintFun1();

constMyClassFun2();

8)修飾類的成員函數(shù)。const修飾符也可以修飾類的成員函數(shù),格式如下:

classClassName

{

public:

intFun()const;

};

這樣,在調(diào)用函數(shù)Fun()時(shí)就不能修改類或?qū)ο蟮膶傩浴?/p>

9)在另一連接文件中引用const常量。使用方式有:

extemconstinti:

externconstintj=10;

第一種用法是正確的;而第二種用法是錯(cuò)誤的,常量不可以被再次賦值。另外,還要注意,常量必須初始化,如constinti=5。

引申2:什么是常引用?

常引用也稱為const引用。之所以引入常引用,是為了避免在使用變量的引用時(shí),在毫不知情的情況下改變了變量的值,從而引起程序錯(cuò)誤。常引用主要用于定義一個(gè)普通變量的只讀屬性的別名,作為函數(shù)的傳入形參,避免實(shí)參在調(diào)用函數(shù)中被意外地改變。

const引用的意思是指向const對(duì)象的引用,非const引用表示指向非const類型的引用。如果既要利用引用提高程序的效率,又要保護(hù)傳遞給函數(shù)的數(shù)據(jù)不在函數(shù)中被改變,就應(yīng)使用常引用。常引用聲明方式:

const類型標(biāo)識(shí)符&引用名=目標(biāo)變量名;

常引用的主要用途如下:

1)用做普通變量的只讀屬性的別名。通常這個(gè)別名只能獲得這個(gè)變量的值,而不能改變這個(gè)變量的值。

2)用于函數(shù)的形參。常引用做形參,可以確保在函數(shù)內(nèi)不會(huì)改變實(shí)參的值,所以參數(shù)傳遞時(shí)盡量使用常引用類型。

如果是對(duì)一個(gè)常量進(jìn)行引用,則編譯器首先建立一個(gè)臨時(shí)變量,然后將該變量的值置入臨時(shí)變量中,對(duì)該引用的操作就是對(duì)該臨時(shí)變量的操作,對(duì)常量的引用可以用其他任何引用來(lái)初始化,但不能改變。

關(guān)于引用的初始化,一般需要注意以下問(wèn)題:當(dāng)初始化值是一個(gè)左值(可以取得地址)時(shí),沒(méi)有任何問(wèn)題;而當(dāng)初始化值不是一個(gè)左值時(shí),則只能對(duì)一個(gè)常引用賦值,而且這個(gè)賦值有一個(gè)過(guò)程,首先將值隱式轉(zhuǎn)換到類型T,然后將這個(gè)轉(zhuǎn)換結(jié)果存放在一個(gè)臨時(shí)對(duì)象里,最后用這個(gè)臨時(shí)對(duì)象來(lái)初始化這個(gè)引用變量。例如下面兩種使用方式:

1)double&dr=1:

2)constdouble&cdr=1:

第1)種方法錯(cuò)誤,初始化值不是左值,而第2)種方法正確,其對(duì)應(yīng)的執(zhí)行過(guò)程如下:

doubletemp=double(1);

constdouble&cdr=temp;

如果對(duì)第1)種使用方法進(jìn)行相應(yīng)的改造,也可以變?yōu)楹戏ǎ纾?/p>

constintival=1024;

1)constint&refVal=ival;

2)int&ref2=ival;

在上例中,第1)種方法的引用是合法的,而第2)種方法的引用是非法的。上例中,可以讀取refVal的值,但是不能修改它,因?yàn)閞efVal的類型是const,任何對(duì)refVal的賦值都是不合法的(const引用是只讀的,常量即不能作為左值的量,定義式中賦初值除外)。同時(shí),const引用可以初始化為不同類型的對(duì)象或者初始化為右值,如字面值常量,而非const引用只能綁定到與該引用同類型的對(duì)象。例如,下述const引用都是合法的。

inti=42;

constint&r=42;

constint&r2=r+i;

在使用const引用進(jìn)行函數(shù)調(diào)用的時(shí)候,需要注意一個(gè)問(wèn)題,例如下面函數(shù)聲明:

voidbar(string&s);

那么下面的表達(dá)式將是非法的:

bar("helloworld");

程序示例如下:

#include<iostream>

#include<string>

usingnamespacestd;

voidbar(string&s)

{

cout<<s<<endl;

}

intmain()

{

bar("helloworld");

return0;

}

程序輸出為

helloworld

原因在于“helloworld”串會(huì)產(chǎn)生一個(gè)臨時(shí)對(duì)象,而在C++中,臨時(shí)對(duì)象是const類型的。因此上面的表達(dá)式就試圖將一個(gè)const類型的對(duì)象轉(zhuǎn)換為非const類型,這是非法的。引用型參數(shù)應(yīng)該在能被定義為const的情況下,盡量定義為const。

3.

switch語(yǔ)句中的case結(jié)尾是否必須添加break語(yǔ)句?為什么正確答案:一般必須在case語(yǔ)句結(jié)尾添加break語(yǔ)句。因?yàn)橐坏┩ㄟ^(guò)switch語(yǔ)句確定了入口點(diǎn),從入口點(diǎn)的case語(yǔ)句開(kāi)始一直往下執(zhí)行,除非遇到關(guān)鍵字break,否則會(huì)執(zhí)行滿足這個(gè)case之后的其他case語(yǔ)句,直到switch結(jié)束或者遇到break為止。如果在switch中省略了break語(yǔ)句,那么匹配的case值后的所有情況(包括default情況)都會(huì)被執(zhí)行。

程序代碼如下:

#include<stdio.h>

intmain()

{

inti;

for(i=0;i<3;i++)

{

switch(i)

{

case0:

printf("%d\n,i);

case2:

printf("%d\n",i);

default:

printf("%d\n",i);

}

}

return0;

}

輸出為

0

0

0

1

2

2

case0的時(shí)候執(zhí)行3次打印,case1的時(shí)候執(zhí)行一次default,case2的時(shí)候執(zhí)行兩次打印。如果將case2后面添加break語(yǔ)句,則最后輸出為0012,因?yàn)榇藭r(shí)case0執(zhí)行兩次,case1執(zhí)行一次default,case2執(zhí)行一次。

需要注意的是,switch(c)語(yǔ)句中c可以是int、long、char、unsignedint等類型,唯獨(dú)不可以是float類型。

4.

volatile在程序設(shè)計(jì)中有什么作用正確答案:編譯器優(yōu)化的時(shí)候可能會(huì)出現(xiàn)問(wèn)題,如當(dāng)遇到多線程編程時(shí),變量的值可能因?yàn)閯e的線程而改變了,而該寄存器的值不會(huì)相應(yīng)改變,從而造成應(yīng)用程序讀取的值和實(shí)際的變量值不一致。例如,在本次線程內(nèi),當(dāng)讀取一個(gè)變量時(shí),為提高存取速度,編譯器優(yōu)化過(guò)程中有時(shí)會(huì)先把變量讀取到一個(gè)寄存器內(nèi);當(dāng)以后再取變量值時(shí),就直接從寄存器中取值;當(dāng)變量值在本線程里改變時(shí),會(huì)同時(shí)把變量的新值復(fù)制到該寄存器中,以便保持一致。

volatile是一個(gè)類型修飾符(typespecitier),它用來(lái)修飾被不同線程訪問(wèn)和修改的變量。被volatile類型定義的變量,系統(tǒng)每次用到它的時(shí)候都是直接從對(duì)應(yīng)的內(nèi)存當(dāng)中提取,而不會(huì)利用cache中的原有數(shù)值,以適應(yīng)它的未知何時(shí)會(huì)發(fā)生的變化,系統(tǒng)對(duì)這種變量的處理不會(huì)做優(yōu)化。所以,volatile一般用于修飾多線程間被多個(gè)任務(wù)共享的變量和并行設(shè)備硬件寄存器等。

對(duì)于volatile關(guān)鍵字的作用,可以通過(guò)在代碼中插入?yún)R編代碼,測(cè)試有無(wú)volatile關(guān)鍵字對(duì)程序最終代碼的影響。

首先建立一個(gè)voltest.cpp文件,輸入下面的代碼:

#include<stdio.h>

intmain()

{

inti=10;

inta=i;

printf("i=%d\n",a);∥下面匯編語(yǔ)句的作用是改變內(nèi)存中i的值,但是又不讓編譯器知道

_asm

{

movdwordptr[ebp-4],20h

}

intb=i;

printf("i=%d\n",b);

return0;

}

在debug調(diào)試版本模式運(yùn)行程序,輸出結(jié)果如下:

i=10

i=32

在release版本模式運(yùn)行程序,輸出結(jié)果如下:

i=10

i=10

輸出的結(jié)果明顯表明,在release模式下,編譯器對(duì)代碼進(jìn)行了優(yōu)化,第二次沒(méi)有輸出正確的i值。把i的聲明加上volatile關(guān)鍵字,程序?qū)嵗缦拢?/p>

#include<stdio.h>

intmain()

{

volatileinti=10;

inta=printf("i=%d\n",a);∥下面匯編語(yǔ)句的作用是改變內(nèi)存中i的值,但是又不讓編譯器知道

printf("i=%d\n",a);∥下面匯編語(yǔ)句的作用是改變內(nèi)存中的值,但是又小讓編譯器知道

_asm

{

movdwordptr[ebp-4],20h

}

intb=i;

printf("i=%d\n",b);

return0;

}

分別在debug調(diào)試版本和release發(fā)布版本運(yùn)行程序,輸出如下所示:

i=10

i=32

一個(gè)定義為volatile的變量是指這個(gè)變量可能會(huì)被意想不到地改變,這樣編譯器就不會(huì)去假設(shè)這個(gè)變量的值了。準(zhǔn)確地說(shuō),優(yōu)化器在用到這個(gè)變量時(shí)必須每次都小心地重新讀取這個(gè)變量的值(FromMemory),而不是使用保存在寄存器里的備份。

5.

斷言ASSERT()是什么正確答案:ASSERT()一般被稱為斷言,它是一個(gè)調(diào)試程序時(shí)經(jīng)常使用的宏。它定義在<assert.h>頭文件中,通常用于判斷程序中是否出現(xiàn)了非法的數(shù)據(jù),在程序運(yùn)行時(shí)它計(jì)算括號(hào)內(nèi)的表達(dá)式的值。如果表達(dá)式的值為false(0),程序報(bào)告錯(cuò)誤,終止運(yùn)行,以免導(dǎo)致嚴(yán)重后果,同時(shí)也便于查找錯(cuò)誤;如果表達(dá)式的值不為0,則繼續(xù)執(zhí)行后面語(yǔ)句。在此需要強(qiáng)調(diào)一點(diǎn),ASSERT()捕獲的是非法情況,而非錯(cuò)誤情況,錯(cuò)誤情況是必然存在的,并且一定需要作出相應(yīng)的處理,而非法情況則不是,它可能只是漏洞而已。

其用法如下:

ASSERT(n!=0);

k=10/n;

需要注意的是,ASSERT()只在Debug版本中有,編譯的Release版本則被忽略。還需要注意的一個(gè)問(wèn)題是ASSERT()與assert()的區(qū)別,ASSERT()是宏,而assert()是ANSIC標(biāo)準(zhǔn)中規(guī)定的函數(shù),它與ASSERT()的功能類似,但是可以應(yīng)用在Release版本中。

使用assert()的缺點(diǎn)是,頻繁的調(diào)用會(huì)極大地影響程序的性能,增加額外的開(kāi)銷。在調(diào)試結(jié)束后,可以通過(guò)在包含#include<assert.h>的語(yǔ)句之前插入#defineNDEBUG來(lái)禁用assert()調(diào)用,示例代碼如下:

#include<stdio.h>

#defineNDEBUG

#include<assert.h>

對(duì)于assert()的使用,需要注意以下幾個(gè)方面:

1)在函數(shù)開(kāi)始處檢驗(yàn)傳入?yún)?shù)的合法性。例如:

assert(nNewSize>=0);

assert(nNewSize<=MAX_BUFFER_SIZE);

2)每個(gè)assert()一般只檢驗(yàn)一個(gè)條件,而不對(duì)多個(gè)條件進(jìn)行檢驗(yàn),因?yàn)橥瑫r(shí)檢驗(yàn)多個(gè)條件時(shí),如果斷言失敗,則無(wú)法直觀地判斷是哪個(gè)條件失敗。例如,assert(nOffset>=0&&nOffset+nSize<=m_nInfomationSize)就不是一種高效的方式,它無(wú)法判斷是nOffset>=0有誤還是nOffset+nSize<=m_nInfomationSize有誤,而將該語(yǔ)句分開(kāi)表示為如下兩個(gè)簡(jiǎn)單語(yǔ)句則更好:assert(nOffset>=0)和assert(nOffset+nSize<=m_nInfomationSize)。

3)不能使用改變環(huán)境的語(yǔ)句,因?yàn)閍ssert只在DEBUG時(shí)生效,如果這么做,會(huì)使程序在真正運(yùn)行時(shí)遇到問(wèn)題。例如,assett(i++<100)就是錯(cuò)誤的。如果執(zhí)行出錯(cuò),在執(zhí)行之前i=100,那么這條語(yǔ)句就不會(huì)執(zhí)行,i++這條命令就沒(méi)有執(zhí)行。而正確的寫(xiě)法應(yīng)該為assert(i<100);i++。

4)并非所有的assert()都能代替過(guò)濾條件,對(duì)于有的地方,assert()無(wú)法達(dá)到條件過(guò)濾的目的。

5)一般在編程的時(shí)候,為了形成邏輯和視覺(jué)上的一致性,會(huì)將assert()與后面的語(yǔ)句之間空一行來(lái)隔開(kāi)。

6.

枚舉變量的值如何計(jì)算正確答案:對(duì)如下程序?qū)嵗M(jìn)行分析。

#include<stdio.h>

intmain()

{

enum{a,b=5,c,d=4,e);

printf("%d%d%d%d%d\n",a,b,c,d,e);

return0;

}

程序輸出為

05645

為什么c的值為6呢?其實(shí),在枚舉中,某個(gè)枚舉變量的值默認(rèn)為前一個(gè)變量的值加1,而如果第一個(gè)枚舉變量沒(méi)有被賦值,則其默認(rèn)值為0。所以在上例中,a,b,c,d,e的值分別為0,5,6,4,5,其中b與e的值都為5,從這個(gè)例子中還可以看出枚舉變量值是可以重復(fù)的。

7.

charstr1[]="abc";charstr2[]="abc";str1與str2不相等,為什么正確答案:兩者不相等。因?yàn)閟tr1和str2都是字符數(shù)組,每個(gè)都有自己的存儲(chǔ)區(qū),它們的值是各存儲(chǔ)區(qū)的首地址。但有些情況卻不一樣,程序示例如下:

#include<iostream>

usingnamespacestd;

intmain()

{

constcharstr3[]="abc";

constcharstr4[]="abc";

constchar*str5="abc";

constchar*str6="abc";

cout<<boolalpha<<(str3==str4)<<endl;

cout<<boolalpha<<(str5==str6)<<endl;

return0;

}

程序輸出為

false

true

為什么上面程序示例的輸出結(jié)果不都是false呢?上例中,str3和str4兩個(gè)字符數(shù)組都存儲(chǔ)在??臻g上,但兩者地址值不相等。而str5和str6并非字符數(shù)組而是字符指針,并不分配存儲(chǔ)區(qū),其后的“abc”以常量形式存于常量區(qū),str5和str6是指它們指向的地址的首地址,而它們自己僅是指向該區(qū)首地址的指針,所以相等(&str5和&str6是指指針自己的地址,所以兩者地址是不相等的)。

8.

為什么有時(shí)候main()函數(shù)會(huì)帶參數(shù)?參數(shù)argc與argv的含義是什么正確答案:C語(yǔ)言的設(shè)計(jì)原則是把函數(shù)作為程序的構(gòu)成模塊。在C99標(biāo)準(zhǔn)中,允許main()函數(shù)沒(méi)有參數(shù),或者有兩個(gè)參數(shù)(有些實(shí)現(xiàn)允許更多的參數(shù),但這只是對(duì)標(biāo)準(zhǔn)的擴(kuò)展)。

命令行參數(shù)有時(shí)用來(lái)啟動(dòng)一個(gè)程序的執(zhí)行,如intmain(intargc,char*argv[]),其中第一個(gè)參數(shù)argc表示命令行參數(shù)的數(shù)目,它是int型的;第二個(gè)參數(shù)argv是一個(gè)指向字符串的指針數(shù)組,由于參數(shù)的數(shù)目并沒(méi)有內(nèi)在的限制,所以argv指向這組參數(shù)值(從本質(zhì)上說(shuō)是一個(gè)數(shù)組)的第一個(gè)元素,這些元素中的每個(gè)都是指向一個(gè)參數(shù)文本的指針。

程序代碼(程序名為a.c)如下:

#include<stdio.h>

intmain(intargc,char*argv[])

{

intcount;

printf("該命令一共有%d個(gè)參數(shù):\n",argc-1);

for(count=1;count<argc;count++)

printf(“%d:%s\n",count,argv[count]);

return0;

}

編譯運(yùn)行,在命令行輸入cIloveyou回車,下面是運(yùn)行該程序的結(jié)果:

該命令一共有3個(gè)參數(shù):

1:I

2:love

3:you

在本例中,程序從命令行中接受了4個(gè)字符串(此處包括程序名),并將它們存儲(chǔ)在字符串?dāng)?shù)組中,其中argv[0]表示a(程序名),argv[1]對(duì)應(yīng)字符串I,argV[2]對(duì)應(yīng)字符串love,argv[3]對(duì)應(yīng)字符串you。argc的值為參數(shù)的個(gè)數(shù),程序自動(dòng)統(tǒng)計(jì)。

同時(shí)需要注意,一個(gè)C語(yǔ)言程序總是從main()函數(shù)開(kāi)始執(zhí)行的。

9.

C++里面是不是所有的動(dòng)作都是main()函數(shù)引起的正確答案:不是。對(duì)于C++程序而言,靜態(tài)變量、全局變量、全局對(duì)象的分配早在main()函數(shù)之前就已經(jīng)完成了。所以并不是所有的動(dòng)作都是由main()引起的,只有編譯器是由main()開(kāi)始執(zhí)行的,main()只不過(guò)是一個(gè)約定的函數(shù)入口,在main()函數(shù)中的顯示代碼執(zhí)行之前,會(huì)調(diào)用一個(gè)由編譯器生成的_main()函數(shù),而_main()函數(shù)會(huì)進(jìn)行所有全局對(duì)象的構(gòu)造及初始化工作。

以如下程序示例代碼為例:

classA{};

Aa;

intmain()

{

...

}

程序在執(zhí)行時(shí),首先初始化全局變量,當(dāng)這個(gè)變量是一個(gè)對(duì)象時(shí),則會(huì)調(diào)用該對(duì)象的構(gòu)造函數(shù),所以上例中,a的構(gòu)造函數(shù)先執(zhí)行,然后再執(zhí)行main()函數(shù)。C++中并非所有的動(dòng)作都是main()引起的。

怎樣在main()函數(shù)退出之后再執(zhí)行一段代碼?答案依然是全局對(duì)象,當(dāng)程序退出時(shí),全局變量必須銷毀,自然會(huì)調(diào)用全局對(duì)象的析構(gòu)函數(shù),所以剩下的就同構(gòu)造函數(shù)一樣了。

10.

*p++與(*p)++等價(jià)嗎?為什么正確答案:在回答這個(gè)問(wèn)題前,必須弄明白一個(gè)問(wèn)題,就是C語(yǔ)言中操作符的優(yōu)先級(jí)問(wèn)題。在C語(yǔ)言中,優(yōu)先級(jí)由高到低的排序主要遵循如下規(guī)則:

1)函數(shù)符號(hào)(),數(shù)組下標(biāo)[],數(shù)組下標(biāo)符號(hào).,成員符號(hào)->,結(jié)合性從左往右。

2)單目運(yùn)算符:!,~,++,--,-(type)*,&,sizeof結(jié)合性從右往左。

3)算術(shù)運(yùn)算法:*、/、%,結(jié)合性從左往右。

4)+、-結(jié)合性從左往右。

5)移位運(yùn)算符:<<,>>,>>>結(jié)合性從左往右。

6)關(guān)系運(yùn)算符:<,<=,>,>=結(jié)合性從左往右。

7)==,!=_結(jié)合性從左往右。

8)邏輯運(yùn)算符:首先,按位運(yùn)算符&、^與|,且&高于^,^高于|,結(jié)合性從左往右;其次,邏輯運(yùn)算符&&與‖,且&&高于‖,結(jié)合性從左往右。

9)三目運(yùn)算符?:,結(jié)合性從右往左;其次是賦值運(yùn)算符=,結(jié)合性從右往左;最后是逗號(hào)運(yùn)算符,結(jié)合性從左往右。

對(duì)于操作符的優(yōu)先級(jí)總結(jié)如下:

1)關(guān)系運(yùn)算符優(yōu)于邏輯運(yùn)算符。

2)移位運(yùn)算符介于算術(shù)運(yùn)算符和比較運(yùn)算符之間。

3)除單目運(yùn)算符外,算術(shù)運(yùn)算符的優(yōu)先級(jí)最高。

所以,因?yàn)閮?yōu)先級(jí)順序的問(wèn)題,*p++與(*p)++并不等價(jià),前者先完成取值操作,然后對(duì)指針地址執(zhí)行++操作;而后者為首先執(zhí)行取值操作,然后對(duì)該值進(jìn)行++運(yùn)算。

11.

前置運(yùn)算與后置運(yùn)算有什么區(qū)別正確答案:以++操作為例,對(duì)于變量a,++a表示取a的地址,增加它的內(nèi)容,然后把值放在寄存器中;a++表示取a的地址,把它的值裝入寄存器,然后增加內(nèi)存中a的值。

一般而言,當(dāng)涉及表達(dá)式計(jì)算時(shí),對(duì)這兩種情況的計(jì)算過(guò)程區(qū)分如下:后置的++運(yùn)算符是先將其值返回,然后其值增1;而前置的++運(yùn)算符,則是先將值增1,再返回其值。程序示例如下:

#include<stdio.h>

intmain()

{

inta,b,c,d;

a=10;

b=a++;

c=++a;

d=10*a++;

printf("%d\n%d\n%d\n%d\n”,a,b,c,d);

return0;

}

程序輸出為

13

10

12

120

上例中,首先賦值a為10,然后執(zhí)行b=a++語(yǔ)句,由于后置操作符的特性,所以首先執(zhí)行b=a操作,即b的值為10,然后執(zhí)行a的自增操作,a的值變?yōu)?1。緊接著執(zhí)行c=++a語(yǔ)句,由于后置操作符的特性,所以首先執(zhí)行a的自增操作,a的值變?yōu)?2,然后執(zhí)行c=a這一賦值操作,所以c的值變?yōu)?2。當(dāng)執(zhí)行d=10*a++語(yǔ)句時(shí),由于++操作符的優(yōu)先級(jí)大于*操作符,所以該語(yǔ)句等價(jià)于d=10*(a++);由于是后置操作符,所以首先執(zhí)行賦值語(yǔ)句,d的值變?yōu)?0*12,即為120,然后a執(zhí)行自增操作,變?yōu)?3,所以最終a、b、c、d的值分別變?yōu)?3、10、12、120。

再如,首先定義inta=4,然后分別執(zhí)行以下5種情況:

1)a+=a++;

2)a+=++a;

3)++a+=a;

4)++a+=a++;

5)++a+=++a;

在VC6.0的環(huán)境下執(zhí)行以上代碼,第1)種情況下,a的值變?yōu)?;第2)種情況下,a的值變?yōu)?0;第3)種情況下,a的值變?yōu)?0;第4)種情況下,a的值變?yōu)?1;第5)種情況下,a的值變?yōu)?2。

需要注意的是,對(duì)于迭代器和其他模板對(duì)象使用前綴形式(++i)的自增、自減運(yùn)算符,一般推薦使用前置自增運(yùn)算,因?yàn)榍爸米栽?++i)通常要比后置自增(i++)效率更高。

12.

a是變量,執(zhí)行(a++)+=a語(yǔ)句是否合法正確答案:為了更好地說(shuō)明本題,首先引入兩個(gè)概念:左值和右值。左值就是可以出現(xiàn)在表達(dá)式左邊的值(等號(hào)左邊),可以被改變,它是存儲(chǔ)數(shù)據(jù)值的那塊內(nèi)存的地址,也稱為變量的地址;右值是指存儲(chǔ)在某內(nèi)存地址中的數(shù)據(jù),也稱為變量的數(shù)據(jù)。左值可以作為右值,但是右值不可以是左值。

本題不合法,a++不能當(dāng)做左值使用。++a可以當(dāng)左值使用。++a表示取a的地址,對(duì)它的內(nèi)容進(jìn)行加1操作,然后把值放在寄存器中。a++表示取a的地址,把它的值裝入寄存器,然后對(duì)內(nèi)存中a的值執(zhí)行加1操作。

所以,對(duì)于如下兩種寫(xiě)法:1)i++=5;2)++i=5;第1)種寫(xiě)法是錯(cuò)誤的,第2)種寫(xiě)法是正確的。i++的運(yùn)算結(jié)果并不是i這個(gè)變量的引用,而是一個(gè)臨時(shí)變量,其值為i的值,所以無(wú)法進(jìn)行i++=5運(yùn)算,甚至編譯器不允許對(duì)一個(gè)臨時(shí)變量重新賦值,上面的表達(dá)式會(huì)引起編譯錯(cuò)誤。

13.

如何進(jìn)行float、bool、int、指針變量與“零值”的比較正確答案:在編寫(xiě)程序時(shí),經(jīng)常需要對(duì)變量與“零值”進(jìn)行比較判斷??疾閷?duì)0值判斷是衡量程序員基本功的重要標(biāo)準(zhǔn),不同變量與零值的判斷,往往方法也不一樣,但很多程序員往往會(huì)存在很多誤區(qū),將NULL、0、1、FALSE、TRUE的意思混淆。例如,把BOOL型變量的0判斷可以寫(xiě)成if(var==0),把int型變量與零值比較寫(xiě)成if(!var),把指針變量與零值的比較寫(xiě)成if(!var),雖然上述寫(xiě)法程序也能正確運(yùn)行,但是未能清晰地表達(dá)程序的意思。

一般地,如果想讓if判斷一個(gè)變量是真還是假,應(yīng)直接使用if(var)、if(!var),表明其為“邏輯”判斷;如果用if判斷一個(gè)數(shù)值型變量(如short、int、long等),應(yīng)該用if(var==0),表明是與0進(jìn)行“數(shù)值”上的比較:而判斷指針則最好使用if(var==NULL)。對(duì)于浮點(diǎn)數(shù)的比較,首先需要考慮到的問(wèn)題就是浮點(diǎn)型變量在內(nèi)存中的存儲(chǔ)導(dǎo)致它并不是一個(gè)精確的數(shù),所以不可以將float變量用“==”或“!=”與數(shù)字比較,應(yīng)該設(shè)法轉(zhuǎn)化成“>=”或“<=”形式。

具體而言,分以下幾種情況:

1)int類型。

if(n==0)

if(n!=0)

不推薦的寫(xiě)法有:

if(n)

if(!n)

因?yàn)檫@樣寫(xiě)容易讓人誤解n是布爾變量。

2)float類型。無(wú)論是float還是double類型的變量,由于它們?cè)趦?nèi)存中的存儲(chǔ)機(jī)制與整型數(shù)不同,有舍入誤差,所以在計(jì)算機(jī)中,大多數(shù)浮點(diǎn)數(shù)都是無(wú)法精確表達(dá)的,很難用A==B來(lái)判定兩個(gè)浮點(diǎn)數(shù)是否相同。在判斷浮點(diǎn)數(shù)相等時(shí),推薦用范圍來(lái)確定,若x在某一范圍內(nèi),就認(rèn)為相等,至于范圍怎么定義,要依據(jù)實(shí)際情況而定,float和double也各有不同。所以都不可以用“==”或“!=”與任何數(shù)字比較,應(yīng)該設(shè)法轉(zhuǎn)化成“>=”或“<=”某個(gè)精度值。具體方式如下所示:

constfloatEPSINON=0.00001:

if((x>=-EPSINO)&&(x<=EPSINON)

上例中EPSINON的取值是0.00001,而一般對(duì)于該值的選取主要是按照實(shí)際情況設(shè)置的。

錯(cuò)誤的寫(xiě)法有以下兩種形式:

if(x==0.0)

if(x!=0.0)

需要注意的是,因?yàn)楦↑c(diǎn)數(shù)的精度誤差,導(dǎo)致對(duì)于確切的兩個(gè)浮點(diǎn)數(shù)a與b,a+b的值和b+a的值永遠(yuǎn)是相等的,而浮點(diǎn)數(shù)的運(yùn)算是不可結(jié)合的,所以(a+b)+c的值和(a+c)+b的值就不一定相等了。

3)bool類型。

if(flag)

if(!flag)

不推薦的寫(xiě)法有:

if(flag==TRUE)

if(flag==FALSE)

if(flag==1)

if(fla==0)

4)指針類型。

if(p==NULL)

if(p!=NULL)

不推薦的寫(xiě)法有:

if(p==0)

if(p!=0)

上述寫(xiě)法容易讓人誤解p是整型變量。

if(p)

if(!p)

上述寫(xiě)法容易讓人誤解p是bool型變量。

在進(jìn)行比較時(shí),有一個(gè)比較容易忽略的問(wèn)題,就是將雙等號(hào)“==”與單等號(hào)“=”混淆。其實(shí)與日常生活中不同的是,在計(jì)算機(jī)領(lǐng)域,單等號(hào)“=”表示的是賦值操作,而雙等號(hào)“==”才表示比較操作。

14.

new/delete與malloc/free的區(qū)別是什么正確答案:在C++中,申請(qǐng)動(dòng)態(tài)內(nèi)存與釋放動(dòng)態(tài)內(nèi)存,用new/delete與malloc/free都可以,而且它們的存儲(chǔ)方式相同,new與malloc動(dòng)態(tài)申請(qǐng)的內(nèi)存都位于堆中,無(wú)法被操作系統(tǒng)自動(dòng)回收,需要對(duì)應(yīng)的delete與free來(lái)釋放空間,同時(shí)對(duì)于一般的數(shù)據(jù)類型,如int、char型,它們的效果一樣。

malloc/free是C/C++語(yǔ)言的標(biāo)準(zhǔn)庫(kù)函數(shù),在C語(yǔ)言中需要頭文件<stdlib.h>的支持,new/delete是C++的運(yùn)算符。對(duì)于類的對(duì)象而言,malloc/free無(wú)法滿足動(dòng)態(tài)對(duì)象的要求,對(duì)象在創(chuàng)建的同時(shí)要自動(dòng)執(zhí)行構(gòu)造函數(shù),對(duì)象消亡之前要自動(dòng)執(zhí)行析構(gòu)函數(shù),而malloc/free不在編譯器控制權(quán)限之內(nèi),無(wú)法執(zhí)行構(gòu)造函數(shù)和析構(gòu)函數(shù)。

具體而言,new/delete與malloc/free的區(qū)別主要表現(xiàn)在以下幾個(gè)方面:

1)new能夠自動(dòng)計(jì)算需要分配的內(nèi)存空間,而malloc需要手工計(jì)算字節(jié)數(shù)。例如,int*p1=newint[2],int*p2=malloc(2*sizeof(int))。

2)new與delete直接帶具體類型的指針,malloc與free返回void類型的指針。

3)new是類型安全的,而malloc不是,例如,int*p=newfloat[2],編譯時(shí)就會(huì)報(bào)錯(cuò);而int*p=malloc(2*sizeof(float)),編譯時(shí)編譯器就無(wú)法指出錯(cuò)誤來(lái)。

4)new一般由兩步構(gòu)成,分別是new操作和構(gòu)造。new操作對(duì)應(yīng)于malloc,但new操作可以重載,可以自定義內(nèi)存分配策略,不做內(nèi)存分配,甚至分配到非內(nèi)存設(shè)備上,而malloc不行。

5)new將調(diào)用構(gòu)造函數(shù),而malloc不能;delete將調(diào)用析構(gòu)函數(shù),而free不能。

6)malloc/free需要庫(kù)文件stdlib.h支持,new/delete則不需要庫(kù)文件支持。

程序示例如下:

#include<iostream>

usingnamespacestd;

classA

{

public:

A()

{

cout<<"Aishere!"<<endl;

}

~A()

{

cout<<"Aisdead!"<<endl;

}

private:

inti;

};

intmain()

{

A*pA=newA;

deletepA;

return0;

}

程序輸出為

Aishere!

Aisdead!

需要注意的是,有資源的申請(qǐng),就有資源的釋放,否則就會(huì)出現(xiàn)資源泄露(也稱內(nèi)存泄露)的問(wèn)題,所以new/delete,malloc/free必須配對(duì)使用。而且delete和free被調(diào)用后,內(nèi)存不會(huì)立即收回,指針也不會(huì)指向空,delete或free僅僅是告訴操作系統(tǒng),這一塊內(nèi)存被釋放了,可以用做其他用途。但是,由于沒(méi)有重新對(duì)這塊內(nèi)存進(jìn)行寫(xiě)操作,所以內(nèi)存中的變量數(shù)值并沒(méi)有發(fā)生變化,出現(xiàn)野指針的情況。因此,釋放完內(nèi)存后,應(yīng)該將指針指向置位空。

程序示例如下:

#include<stdio.h>

#include<stdlib.h>

#include<string.h>

voidTestFree()

{

char*str=(char*)malloc(100);

strcpy(str,"hello");

free(str);

if(str!=NULL)

{

strcpy(str,"world");

printf("%s\n",str);

}

}

intmain()

{

TestFree();

return0;

}

程序輸出為

world

通過(guò)上例可知,free或delete調(diào)用后,內(nèi)存其實(shí)并沒(méi)有釋放,也沒(méi)有為空,而是還存儲(chǔ)有內(nèi)容,所以在將資源free或delete調(diào)用后,還需要將其置為NULL才行。

此時(shí),便產(chǎn)生了一個(gè)問(wèn)題,既然new/delete的功能完全覆蓋了malloc/free,為什么在C++中沒(méi)有取消掉malloc/free,而是仍然將其保留了?其實(shí),由于C++程序經(jīng)常要調(diào)用C函數(shù),而C程序只能用malloc/free管理動(dòng)態(tài)內(nèi)存,所以仍然保留了malloc/free。

15.

什么時(shí)候需要將引用作為返回值正確答案:將引用作為函數(shù)返回值類型的格式如F所不:

類型標(biāo)識(shí)符&函數(shù)名(形參列表及類型說(shuō)明){∥函數(shù)體}

將引用作為返回值的優(yōu)點(diǎn)是在內(nèi)存中不產(chǎn)生被返回值的副本,從而大大提高了程序的安全性與效率。

具體而言,將引用作為函數(shù)返回值類型的格式一般需要注意以下4點(diǎn)內(nèi)容:

1)不能返回局部變量的引用。局部變量由于存儲(chǔ)在棧區(qū),在函數(shù)返回后會(huì)被銷毀,因此被返回的引用就成為了“無(wú)所指”的引用,程序會(huì)進(jìn)入未知狀態(tài),引起程序錯(cuò)誤甚至崩潰。

2)不能返回函數(shù)內(nèi)部new分配的內(nèi)存的引用。例如,被函數(shù)返回的引用只是作為一個(gè)臨時(shí)變量出現(xiàn),而沒(méi)有被賦予一個(gè)實(shí)際的變量,那么這個(gè)引用所指向的空間(由new分配)就無(wú)法釋放,造成內(nèi)存泄露。

3)可以返回類成員的引用,但最好是常引用類型。當(dāng)對(duì)象的屬性與某種業(yè)務(wù)規(guī)則相關(guān)聯(lián)時(shí),其賦值常常與某些其他屬性或?qū)ο蟮臓顟B(tài)有關(guān),因此有必要將賦值操作封裝在一個(gè)業(yè)務(wù)規(guī)則當(dāng)中。如果其他對(duì)象可以獲得該屬性的非常量引用(或指針),那么對(duì)該屬性的單純賦值就會(huì)破壞業(yè)務(wù)規(guī)則的完整性。

4)流操作符<<和>>。一般這兩個(gè)操作符連續(xù)使用,因此這兩個(gè)操作符的返回值應(yīng)該是一個(gè)仍然支持這兩個(gè)操作符的流引用。在另外的一些操作符中,不能返回引用+-*/四則運(yùn)算符。由于這4個(gè)操作符沒(méi)有副作用,因此它們必須構(gòu)造一個(gè)對(duì)象作為返回值,可選的方案包括返回一個(gè)對(duì)象,返回一個(gè)局部變量的引用,返回一個(gè)new分配的對(duì)象的引用,返回一個(gè)靜態(tài)對(duì)象引用。根據(jù)前面提到的引用作為返回值的3個(gè)規(guī)則,第2)、3)兩個(gè)方案都被否決了。靜態(tài)對(duì)象的引用又因?yàn)?(a+b)==(c+d))會(huì)永遠(yuǎn)為true而導(dǎo)致錯(cuò)誤,所以可選的只剩下返回一個(gè)對(duì)象了。

16.

變量名為618Software是否合法正確答案:變量名618Soflware不合法。在C語(yǔ)言中,變量名、函數(shù)名、數(shù)組名統(tǒng)稱為標(biāo)識(shí)符,C語(yǔ)言規(guī)定標(biāo)識(shí)符只能由字母(a~z,A~Z)、數(shù)字(0~9)、下畫(huà)線(_)組成,并且標(biāo)識(shí)符的第一個(gè)字符必須是字母或下畫(huà)線,不能以數(shù)字開(kāi)頭,不能包含除了“_”以外的任何特殊字符,如%、#等,不能包含空白字符(換行符、空格和制表符)。

以下標(biāo)識(shí)符都是非法的。

1)char:char是C語(yǔ)言的一個(gè)數(shù)據(jù)類型,是保留字,不能作為標(biāo)識(shí)符,其他的如int、float等類似。

2)numberofbook:標(biāo)識(shí)符中不能有空格。

3)3com:以數(shù)字開(kāi)頭。

4)a*b:*不能作為標(biāo)識(shí)符的字符。

值得注意的是,C語(yǔ)言是區(qū)分大小寫(xiě)的,例如Count與count被認(rèn)為是兩個(gè)不同的標(biāo)識(shí)符,這一點(diǎn)與其他語(yǔ)言不一樣。

17.

C語(yǔ)言中,整型變量x小于0,是否可知x×2也小于0正確答案:假定計(jì)算機(jī)是32位的,用2的補(bǔ)碼表示整數(shù),若x<0,則.x×2<0不一定成立。例如,當(dāng)x為整型值的最小時(shí)就不成立。

程序示例代碼如下:

#include<stdio.h>

intmain()

{

intx=-4292967295;

if(2*x<0)

printf("2*x<0\n");

else

printf("2*x>0\n");

return0;

}

程序輸出為

2*x>0

18.

exit(status)是否跟從main()函數(shù)返回的status等價(jià)正確答案:在C語(yǔ)言標(biāo)準(zhǔn)中,它們是等價(jià)的,但是如果在退出的時(shí)候需要使用main()函數(shù)的局部數(shù)據(jù),那么從main()函數(shù)中使用return()就不行了。

exit()函數(shù)與return()的功能見(jiàn)下表。exit函數(shù)與return的功能函數(shù)功能return返回函數(shù)調(diào)用,如果返回的是main()函數(shù),則為退出程序exit在調(diào)用處強(qiáng)行退出程序,運(yùn)行一次程序就結(jié)束。exit(0)是程序結(jié)束時(shí)返回0給系統(tǒng),正常退出;exh(1)程序結(jié)束時(shí)返回1給系統(tǒng);exit(n)程序結(jié)束時(shí)返回n給系統(tǒng)

對(duì)于exit()函數(shù)而言,無(wú)論參數(shù)是幾,其效果都是相同的,不同之處在于程序員可以用不同的數(shù)字來(lái)區(qū)別退出的原因,從而方便判斷程序的異常問(wèn)題。例如,內(nèi)存分配失敗是exit(1),打開(kāi)文件失敗是exit(2)或者用來(lái)標(biāo)示在此處退出。

19.

已知String類定義,如何實(shí)現(xiàn)其函數(shù)體正確答案:String類定義如下:

classString

{

public:

String(constchar*str=NULL);

∥通用構(gòu)造函數(shù)

String(conststring&another);

∥復(fù)制構(gòu)造函數(shù)

~String();

∥析構(gòu)函數(shù)

String&operator=(constString&rhs);

∥賦值函數(shù)

private:

char*mdata;

∥用于保存字符串

};

在這個(gè)類中包括了指針類成員變量m_data,所以需要自定義其復(fù)制構(gòu)造函數(shù)、賦值運(yùn)算操作符函數(shù),避免單純的指針值的復(fù)制。

具體而言,String類的函數(shù)體實(shí)現(xiàn)代碼如下:

#include<iostream>

usingnamespacestd;

classString

{

public;

Stringr(constchar*str=NULL);

∥通用構(gòu)造函數(shù)

string(constString&another);

∥復(fù)制構(gòu)造函數(shù)

~String();

∥析構(gòu)函數(shù)

String&operator=(constString&rhs);

∥賦值函數(shù)

private:

char*mdata:

∥用于保存字符串

};

String::String(constchar*str)

if(str==NULL)

{

if(str==NULL)

{

m_data=newchar[1];

m_data[0]='\0';

}

else

{

m_data=newchar[strlen(str)+1];

strcpy(m_data,str);

}

}

String::String(constString&another)

{

m_data=newchar[strlen(another.m_data)+1];

strcpy(m_data,another.m_data);

}

String::~String()

{

delete[]m_data;

}

String&String::operator==(constString&rhs)

{

if(this==&rhs)

return*this;

delete[]m_data;

mdata=newchar[strlen(rhs.m_data)+1];

strcpy(m_data,rhs.m_data);

return*this;

}

intmain()

{

Stringa("abcdefg");

printf("%s\n",a);

Stringb(a);

printf("%s\n",b);

Stringc=b;

printf("%s\n",c);

return0;

}

程序輸出為

abcdefg

abcdefg

abcdefg

20.

在C++中如何實(shí)現(xiàn)模板函數(shù)的外部調(diào)用正確答案:export是C++新增的關(guān)鍵字,它的作用是實(shí)現(xiàn)模板函數(shù)的外部調(diào)用,類似于extern關(guān)鍵字。為了訪問(wèn)其他代碼文件中的變量或?qū)ο螅瑢?duì)普通類型(包括基本數(shù)據(jù)類、結(jié)構(gòu)和類)可以利用關(guān)鍵字extern來(lái)使用這些變量或?qū)ο螅珜?duì)于模板類型,則可以在頭文件中聲明模板類和模板函數(shù),在代碼文件中使用關(guān)鍵字export來(lái)定義具體的模板類對(duì)象和模板函數(shù),然后在其他用戶代碼文件中,包含聲明頭文件后,就可以使用這些對(duì)象和函數(shù)了。使用方式如下:

externintn;

externstructPointp;

externclassAa;

expoortemplate<classT>classStack<int>s;

exporttemplate<classT>voidf(T&t){...}

21.

在C++上中,關(guān)鍵字explicit有什么作用正確答案:在C++中,如下聲明是合法的。

classString

{

String(constchar*p);

...

}

Strings1="hello";

上例中,Strings1="hello"會(huì)執(zhí)行隱式轉(zhuǎn)換,等價(jià)于Strings1=String("hello")。為了避免這種情況的發(fā)生,C++引入了關(guān)鍵字explicit,它可以阻止不應(yīng)該允許的經(jīng)過(guò)轉(zhuǎn)換構(gòu)造函數(shù)進(jìn)行的隱式轉(zhuǎn)換的發(fā)生,聲明為explicit的構(gòu)造函數(shù)不能在隱式轉(zhuǎn)換中使用。

在C++中,一個(gè)參數(shù)的構(gòu)造函數(shù)(或者除了第一個(gè)參數(shù)外其余參數(shù)都有默認(rèn)值的多參構(gòu)造函數(shù))一般具備兩個(gè)功能:構(gòu)造器和默認(rèn)且隱含的類型轉(zhuǎn)換操作符。所以,當(dāng)AAA=XXX,恰好XXX的類型正好是AAA單參數(shù)構(gòu)造器的參數(shù)類型,這時(shí)候編譯器就自動(dòng)調(diào)用這個(gè)構(gòu)造器,創(chuàng)建一個(gè)AAA的對(duì)象。而在某些情況下,卻違背了程序員的本意。此時(shí)就要在這個(gè)構(gòu)造器前面加上explicit修飾,指定這個(gè)構(gòu)造器只能被明確地調(diào)用、使用,不能作為類型轉(zhuǎn)換操作符被隱含地使用。

程序代碼如下:

classTest1

{

public:

Test1(intn){num=n;}∥普通構(gòu)造函數(shù)

private:

intnum;

};

classTest2

{

public:

explicitTest2(intn){num=n;)

∥explicit(顯式)構(gòu)造函數(shù)

private:

intnum;

};

intmain()

{

Test1t1=12;

∥隱式調(diào)用其構(gòu)造函數(shù),成功

Test2t2=12;

∥編譯錯(cuò)誤,不能隱式調(diào)用其構(gòu)造函數(shù)

Test2t3(12);

∥顯示調(diào)用成功

return0;

}

Test1的構(gòu)造函數(shù)帶一個(gè)int型的參數(shù),Test1t1=12會(huì)隱式轉(zhuǎn)換成調(diào)用Test1的這個(gè)構(gòu)造函數(shù),而Test2的構(gòu)造函數(shù)被聲明為explicit(顯式),這表示不能通過(guò)隱式轉(zhuǎn)換來(lái)調(diào)用這個(gè)構(gòu)造函數(shù),因此Test2t2=12會(huì)出現(xiàn)編譯錯(cuò)誤。普通構(gòu)造函數(shù)能夠被隱式調(diào)用,而explicit()構(gòu)造函數(shù)只能被顯式調(diào)用。

22.

C++中異常的處理方法以及使用了哪些關(guān)鍵字正確答案:C++異常處理使用的關(guān)鍵字有try、catch、throw。C++中的異常處理機(jī)制只能處理由throw捕獲的異常,沒(méi)有捕獲的將被忽略。使用try{}catch(){}語(yǔ)句來(lái)捕獲異常,把可能發(fā)生異常的代碼放在try{}語(yǔ)句塊中,后面跟若干個(gè)catch(){}負(fù)責(zé)處理具體的異常類型,這樣一組有try塊和不少于一個(gè)的catch塊就構(gòu)成了一級(jí)異常捕獲。如果本級(jí)沒(méi)有帶適當(dāng)類型參數(shù)的catch塊,將不能捕獲異常,異常就會(huì)向上一級(jí)傳遞,函數(shù)調(diào)用處如果沒(méi)有捕獲住異常,則直接跳到更高一層的調(diào)用者,如果一直沒(méi)有捕獲該異常,C++會(huì)使用默認(rèn)的異常處理函數(shù),該函數(shù)可能會(huì)讓程序最終跳出main()函數(shù)并導(dǎo)致程序異常終止。

catch的作用是捕獲異常,finally不管代碼是否有異常都執(zhí)行。try中如果有return,仍然需要執(zhí)行finally語(yǔ)句。此種情況的執(zhí)行過(guò)程如下:

1)執(zhí)行return返回語(yǔ)句(return之后的語(yǔ)句內(nèi)容),計(jì)算返回值,暫存在一個(gè)臨時(shí)變量中。

2)執(zhí)行finally語(yǔ)句塊。

3)return原來(lái)已經(jīng)計(jì)算得到的結(jié)果值。

如果在finally區(qū)段中又調(diào)用了一次return語(yǔ)句,則try區(qū)段中的返回值將會(huì)被遮掩,使得方法調(diào)用者得到的是finally區(qū)段中的返回值,這常常又與程序編寫(xiě)的初衷相背。

23.

如何定義和實(shí)現(xiàn)一個(gè)類的成員函數(shù)為回調(diào)函數(shù)正確答案:回調(diào)函數(shù)就是被調(diào)用者回頭調(diào)用的函數(shù),它是一個(gè)通過(guò)函數(shù)指針調(diào)用的函數(shù)。如果把函數(shù)的指針(地址)作為參數(shù)傳遞給另一個(gè)函數(shù),當(dāng)這個(gè)指針被用為調(diào)用它所指向的函數(shù)時(shí),此時(shí)就可以稱它為回調(diào)函數(shù)?;卣{(diào)函數(shù)不是由該函數(shù)的實(shí)現(xiàn)方直接調(diào)用的,而是在特定的事件或條件發(fā)生時(shí)由另外的一方調(diào)用的,用于對(duì)該事件或條件進(jìn)行響應(yīng)。

使用回調(diào)函數(shù)實(shí)際上就是在調(diào)用某個(gè)函數(shù)(通常是API函數(shù))時(shí),將自己的一個(gè)函數(shù)(這個(gè)函數(shù)為回調(diào)函數(shù))的地址作為參數(shù)傳遞給那個(gè)被調(diào)用函數(shù)。而該被調(diào)用函數(shù)在需要的時(shí)候,利用傳遞的地址調(diào)用回調(diào)函數(shù)。

回調(diào)函數(shù)由程序員自己編寫(xiě),當(dāng)需要調(diào)用另外一個(gè)函數(shù)時(shí),這個(gè)函數(shù)的其中一個(gè)參數(shù)就是這個(gè)回調(diào)函數(shù)名。系統(tǒng)在必要的時(shí)候就會(huì)調(diào)用程序員寫(xiě)的回調(diào)函數(shù),這樣就可以在回調(diào)函數(shù)里完成要做的事。

要定義和實(shí)現(xiàn)一個(gè)類的成員函數(shù)為回調(diào)函數(shù)需要做3件事:

1)聲明。

2)定義。

3)設(shè)置觸發(fā)條件,就是在函數(shù)中把回調(diào)函數(shù)名作為一個(gè)參數(shù),以便系統(tǒng)調(diào)用。

聲明回調(diào)函數(shù)類型示例如下:

typedefvoid(*FunPtr)(void);

∥定義回調(diào)函數(shù)

classA

{

public:

∥回調(diào)函數(shù),必須聲明為static

staticvoidcallBackFun(void)

{

...

}

};

∥設(shè)置觸發(fā)條件

voidFuntype(FunPtrp)

{

p();

}

voidmain(void)

{

Funtype(A::callBackFun);

}

回調(diào)函數(shù)與應(yīng)用程序接口(API)非常接近,它們都是跨層調(diào)用的函數(shù),但區(qū)別是API是低層提供給高層的調(diào)用,一般這個(gè)函數(shù)對(duì)高層都是已知的;而回調(diào)函數(shù)正好相反,它是高層提供給底層的調(diào)用,對(duì)于低層它是未知的,必須由高層進(jìn)行安裝,這個(gè)安裝函數(shù)其實(shí)就是一個(gè)低層提供的API,安裝后低層不知道這個(gè)回調(diào)的名字,但它通過(guò)一個(gè)函數(shù)指針來(lái)保存這個(gè)回調(diào)函數(shù),在需要調(diào)用時(shí),只需引用這個(gè)函數(shù)指針和相關(guān)的參數(shù)指針即可。

24.

內(nèi)存分配的形式有哪些正確答案:一個(gè)C/C++編譯的程序所占用的系統(tǒng)內(nèi)存一般分為以下幾個(gè)部分的內(nèi)容:

1)由符號(hào)起始的區(qū)塊(BlockStartedbySymbol,BSS)段:BSS段通常是指用來(lái)存放程序中未初始化的全局?jǐn)?shù)據(jù)和靜態(tài)數(shù)據(jù)的一塊內(nèi)存區(qū)域。BSS段屬于靜態(tài)內(nèi)存分配,程序結(jié)束后靜態(tài)變量資源由系統(tǒng)自動(dòng)釋放。

2)數(shù)據(jù)段(datasegment):數(shù)據(jù)段通常是指用來(lái)存放程序中已初始化的全局變量的一塊內(nèi)存區(qū)域。數(shù)據(jù)段也屬于靜態(tài)內(nèi)存分配。

3)代碼段(codesegment/textsegment):代碼段也叫文本段,通常是指用來(lái)存放程序執(zhí)行代碼(包括類成員函數(shù)和全局函數(shù)以及其他函數(shù)代碼)的一塊內(nèi)存區(qū)域,這部分區(qū)域的大小在程序運(yùn)行前就已經(jīng)確定,并且內(nèi)存區(qū)域通常是只讀,某些架構(gòu)也允許代碼段為可寫(xiě),即允許修改程序。在代碼段中,也有可能包含一些只讀的常數(shù)變量,如字符串常量。這個(gè)段一般是可以被共享的,如在Linux系統(tǒng)中打開(kāi)了兩個(gè)Vi來(lái)編輯文本,那么一般來(lái)說(shuō)這兩個(gè)Vi是共享一個(gè)代碼段的。

4)堆(heap):堆用于存放進(jìn)程運(yùn)行中被動(dòng)態(tài)分配的內(nèi)存段,它的大小并不固定,可動(dòng)態(tài)擴(kuò)張或縮減。當(dāng)進(jìn)程調(diào)用malloc或new等函數(shù)分配內(nèi)存時(shí),新分配的內(nèi)存就被動(dòng)態(tài)添加到堆上(堆被擴(kuò)張),當(dāng)利用free或delete等函數(shù)釋放內(nèi)存時(shí),被釋放的內(nèi)存從堆中被刪除(堆被縮減)。堆一般由程序員分配釋放,若程序員不釋放,程序結(jié)束時(shí)可能由操作系統(tǒng)回收。需要注意的是,它與數(shù)據(jù)結(jié)構(gòu)中的堆是兩回事,分配方式類似于鏈表。

5)棧(stack):棧用戶存放程序臨時(shí)創(chuàng)建的局部變量,一般包括函數(shù)括弧“{}”中定義的變量(但不包括static聲明的變量,static意味著在數(shù)據(jù)段中存放變量)。除此之外,在函數(shù)被調(diào)用時(shí),其參數(shù)也會(huì)被壓入發(fā)起調(diào)用的進(jìn)程棧中,并且等到調(diào)用結(jié)束后,函數(shù)的返回值也會(huì)被存放回棧中。棧由編譯器自動(dòng)分配釋放,存放函數(shù)的參數(shù)值、局部變量的值等。其操作方式類似于數(shù)據(jù)結(jié)構(gòu)中的棧。棧內(nèi)存分配運(yùn)算內(nèi)置于處理器的指令集中,一般使用寄存器來(lái)存取,效率很高,但是分配的內(nèi)存容量有限。

需要注意的是,代碼段和數(shù)據(jù)段之間有明確的分隔,但是數(shù)據(jù)段和堆棧段之間沒(méi)有,而且棧是向下增長(zhǎng)的,堆是向上增長(zhǎng)的。程序示例如下:

#include<stdio.h>

#include<stdlib.h>

#include<string.h>

intglobal=0;

∥全局初始化區(qū)

char*p1;

∥全局未初始化區(qū)

intmain()

{

inta;

∥棧

chars[]="abcdefg";

∥棧

char*p2;

∥棧

char*p3="123456789";

∥123456789在常量區(qū),p3在棧上

staticintc=0;

∥全局(靜態(tài))初始化區(qū)

p1=(char*)malloc(100);

p2=(char*)malloc(200);

∥分配得來(lái)的100和200B的區(qū)域就在堆區(qū)

strcpy(p1,"123456789");

∥123456789放在常量區(qū),編譯器可能會(huì)將它與p3所指向的

∥"123456789"優(yōu)化成一個(gè)地方

return0;

}

除了全局靜態(tài)對(duì)象,還有局部靜態(tài)對(duì)象和類的靜態(tài)成員,局部靜態(tài)對(duì)象是在函數(shù)中定義的,就像棧對(duì)象一樣,只不過(guò),其前面多了static關(guān)鍵字。局部靜態(tài)對(duì)象的生命期是從其所在函數(shù)第一次被調(diào)用,更確切地說(shuō),是當(dāng)?shù)谝淮螆?zhí)行到該靜態(tài)對(duì)象的聲明代碼時(shí),產(chǎn)生該靜態(tài)局部對(duì)象,直到整個(gè)程序結(jié)束時(shí),才銷毀該對(duì)象。類的靜態(tài)成員的生命周期是該類的第一次調(diào)用到程序的結(jié)束。

25.

什么是內(nèi)存泄露正確答案:堆是動(dòng)態(tài)分配內(nèi)存的,并且可以分配使用很大的內(nèi)存,使用不好會(huì)產(chǎn)生內(nèi)存泄露。頻繁地使用malloc和free會(huì)產(chǎn)生內(nèi)存碎片(類似磁盤(pán)碎片)。

所謂內(nèi)存泄露(memoryleak)是指由于疏忽或錯(cuò)誤造成程序未能釋放已經(jīng)不再使用的內(nèi)存的情況。一般常說(shuō)的內(nèi)存泄露是指堆內(nèi)存的

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(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)論