【C++】C++常見面試題彙總,持續更新中…
1:指標(*)、引用(&)、解引用(*)、取地址(&)、的概念和區別
概念:
指標指向一塊記憶體,指標儲存的是記憶體的地址;引用是變數的別名,本質是引用該變數的地址。
解引用是取指標指向的地址的內容,取地址是獲得變數在記憶體中的地址。
區別:
(1)引用使用是無需解引用,指標需解引用。
(2)引用不能為空,指標可以為空。
(3)引用在定義時被初始化一次,之後不可變;指標指向的值和本身的值是可變的,也就是說指標只是一塊地址,地址裡的東西可變。
(4)程式會給指標變數分配記憶體區域,而引用不需要分配記憶體區域。
2:memset、memcpy和strcpy的區別
memcpy是記憶體拷貝函式,可以拷貝任何資料型別的物件,例如memcpy(b, a, sizeof(b))。
strcpy只能拷貝字串,遇到’ ′結束拷貝。
memset用來對一段記憶體空間全部設定為某個字元,例如:char a[100];memset(a, “, sizeof(a))。
3:struct和class的區別,struct與union的區別
struct和class都是宣告類的關鍵字
區別是:
(1)在預設情況下,struct的成員變數是公共(public)的;在預設情況下,class的成員變數是私有(private)的。
(2)struct保證成員按照宣告順序在記憶體中儲存。class不能保證。
(3)對於繼承來說,class預設是private繼承,struct預設是public繼承。
區別是(union和class同理):
(1)一個union型別的變數,所有成員變數共享一塊記憶體,該記憶體的大小有這些成員變數中長度最大的一個來決定,
struct中成員變數記憶體都是獨立的。
(2)union分配的記憶體是連續的,而struct不能保證分配的記憶體是連續的。
struct與union的區別:
(1)struct與union都由多個不同的資料型別成員組成。但是, union的成員共享儲存空間一塊地址空間,而struct的成員則不是。
(2)因此,對於union的一個成員賦值, 那麼其它成員會重寫,而struct則不會
4:指標在16位機、32位機、64位機分別佔用多少個位元組
16位機–2位元組、32位機–4位元組、64位機–8位元組。
5:如何引用一個已經定義過的全域性變數?區別是什麼
如果在同一個檔案中,直接引用即可。
如果不在同一個檔案,有兩種方式:
(1)直接引用標頭檔案就可以使用了。
(2)用extern關鍵字重新宣告一下。
6:全域性變數可不可以定義在可被多個.C檔案包含的標頭檔案中?因為全域性變數的作用域是整個源程式,可以宣告多次,但是隻能定義一次。變數的宣告一般放在標頭檔案中,那麼變的定義可以放在標頭檔案中嗎?在實際的程式設計中一般很少在標頭檔案中定義全域性變數,因為多次引用可能重定義。7:do……while和while……do有什麼區別?
do…while先執行迴圈再判斷條件,while…do先判斷條件再執行迴圈。
8:對於一個頻繁使用的短小函式,在C語言中應用什麼實現,在C++中應用什麼實現?
C用巨集定義,C++用inline。9:main 函式執行以前,會執行什麼程式碼?
全域性物件的建構函式會在main 函式之前執行,比如int a;初始化為0。
10:main 主函式執行完畢後,會執行什麼程式碼?
可以,使用on_exit 註冊的函式會在程式碼執行完畢後執行:
void main( void )
{
String str(“zhanglin”);
on_exit( fn1 );
on_exit( fn2 );
on_exit( fn3 );
on_exit( fn4 );
printf( “This is executed first.
” );
}
int fn1()
{
printf( “next.
” );
return 0;
}
11:區域性變數能否和全域性變數重名?
可以,但是區域性會遮蔽全域性。要用全域性變數,需要使用域作用符“::”。
12:描述記憶體分配方式以及它們的區別?1.從靜態儲存區域分配。該儲存區域在程式編譯的時候就已經分配好了,這塊記憶體在程式的整個執行期間都存在。例如全域性變數,static 變數。
2. 在棧上建立。在執行函式時,函式的區域性變數儲存在該區域,函式執行結束時會釋放該儲存空間。棧記憶體分配運算內建於處理器的指令集。
3. 從堆上分配,亦稱動態記憶體分配。程式在執行的時候用malloc 或new 申請任意多少的記憶體,程式設計師自己負責在何時用free 或delete 釋放記憶體。 動態記憶體的生存期由程式設計師決定,使用非常靈活。
13:類的成員函式過載、覆蓋和隱藏的概念和區別?概念:過載是指再同一個作用域內,有幾個同名的函式,但是引數列表的個數和型別不同。 函式覆蓋是指派生類函式覆蓋基類函式,函式名、引數型別、返回值型別一模一樣。派生類的物件會呼叫子類中的覆蓋版本,覆蓋父類中的函式版本。 “隱藏”是指派生類的函式遮蔽了與其同名的基類函式。覆蓋和過載的區別:函式是否處在不同的作用域,引數列表是否一樣;基類函式是否有virtual關鍵字。
隱藏和覆蓋的區別:
(1)派生類的函式與基類的函式同名,但是引數不同。此時,不論有無virtual關鍵字,基類的函式將被隱藏。
(2)派生類的函式與基類的函式同名,引數也相同,但是基類函式沒有virtual 關鍵字。此時,基類的函式被隱藏有virtual,就是覆蓋。
如果子類覆蓋父類的函式但是不加virtual ,也能實現多型,由於virtual修飾符會被隱形繼承,但是儘量加上。
14:static關鍵字?
為什麼引入static:
編譯器為區域性變數在棧上分配空間,但是函式執行結束時會釋放掉。所以static可以解決函式執行完後變數值被釋放的問題,static變數儲存在靜態儲存區。
缺點:
不安全,因為作用域是全域性的。
優點:
因為靜態變數對所有物件所公有的,可以節省記憶體,提高時間效率。
靜態資料成員使用方式:
<類名>::<靜態成員名>
作用:
(1)可以用於全域性變數的定義:為該變數分配靜態儲存區。程式執行結束前不會被釋放。
(2)宣告和定義靜態成員函式:表示該函式為靜態函式,只能在本檔案中被呼叫。
(3)定義靜態區域性變數:只被初始化一次,只有程式執行結束才會釋放。區別是作用域的範圍。
15:const與#define的概念和優缺點?
const用來定義常量、修飾函式引數、修飾函式返回值,可以避免被修改,提高程式的健壯性。
define是巨集定義,在編譯的時候會進行替換,這樣做的話可以避免沒有意義的數字或字串,便於程式的閱讀。
區別:
1.const定義的資料有資料型別,而巨集常量沒有資料型別。編譯器可以對const常量進行型別檢查。而對巨集定義只進行字元替換,沒有型別安全檢查,所以字元替換時可能出錯。
例子:
寫一個“標準”巨集MIN,這個巨集輸入兩個引數並返回較小的一個。
#define MIN(A,B) ((A) <= (B) (A) : (B))
least = MIN(a, b);
下面的關鍵字const是什麼含意:
const int a;//a是一個常整型數
int const a;//a是一個常整型數
const int *a;//a是一個指向常整型數的指標
int * const a;//a是一個指向整型數的常指標
int const * a const;//a是一個指向常整型數的常指標
static關鍵字的作用:
(1)函式體內static變數的作用範圍為該函式體,不同於auto變數,該變數的記憶體只被分配一次,因此其值在下次呼叫時仍維持上 次的值;
(2)在模組內的static全域性變數可以被模組內所用函式訪問,但不能被模組外其它函式訪問;
(3)在模組內的static函式只可被這一模組內的其它函式呼叫,這個函式的使用範圍被限制在宣告它的模組內;
(4)在類中的static成員變數屬於整個類所擁有,對類的所有物件只有一份拷貝;
(5)在類中的static成員函式屬於整個類所擁有,這個函式不接收this指標,因而只能訪問類的static成員變數。
const關鍵字的作用:
(1)欲阻止一個變數被改變,可以使用const關鍵字。在定義該const變數時,通常需要對它進行初始化,因為以後就沒有機會再去改變它了;
(2)對指標來說,可以指定指標本身為const,也可以指定指標所指的資料為const,或二者同時指定為const;
(3)在一個函式宣告中,const可以修飾形參,表明它是一個輸入引數,在函式內部不能改變其值;
(4)對於類的成員函式,若指定其為const型別,則表明其是一個常函式,不能修改類的成員變數;
(5)對於類的成員函式,有時候必須指定其返回值為const型別,以使得其返回值不為“左值”。例如:
16:堆疊溢位的原因?
沒有回收垃圾資源
棧溢位:
一般都是由越界訪問導致的。例如區域性變數陣列越界訪問或者函式內區域性變數使用過多,超出了作業系統為該程式分配的棧的大小。
堆溢位:
由於堆是使用者申請的,所以溢位的原因可能是程式設計師申請了資源但是忘記釋放了。
17:重新整理緩衝區方式?
換行重新整理緩衝區:printf(“
”);程式結束重新整理緩衝區:return 0;18:類和物件的兩個基本概念?類的作用或概念:用來描述一組具有相似屬性的東西的物件的一種資料結構。類中有資料成員的宣告和定義,有成員函式的實現程式碼。物件就是類的例項化。計算機中想要使用類,只能進行例項化。
19:介紹一下STL,詳細說明STL如何實現vector。
STL是標準模版庫,由容器演算法迭代器組成。
STL有以下的一些優點:
(1)可以很方便的對一堆資料進行排序(呼叫sort());
(2)除錯程式時更加安全和方便;
(3)stl是跨平臺的,在linux下也能使用。
vector實質上就是一個動態陣列,會根據資料的增加,動態的增加陣列空間。
什麼是容器。如何實現?
容器是一種類型別,用來儲存資料
STL有7種主要容器:vector,list,deque,map,multimap,set,multiset.
20:變數的宣告和定義有什麼區別
變數的宣告是告訴編譯器我有某個型別的變數,但不會為其分配記憶體。但是定義會分配了記憶體。
21:簡述#define #endif 和#ifndef的作用
這三個命令一般是為了避免標頭檔案被重複引用。
#ifndef CH_H //意思是如果沒有引用ch.h
#define CH_H //引用ch.h
#endif //否則不需要引用
22:引用與指標有什麼區別?
(1) 引用必須被初始化,指標不必。
(2) 引用初始化以後不能被改變,指標可以改變所指的物件。
(3) 不存在指向空值的引用,但是存在指向空值的指標。
23:C++繼承機制?
n類成員的訪問控制方式
public:類本身、派生類和其它類均可訪問;
protected:類本身和派生類均可訪問,其它類不能訪問;
private(預設):類本身可訪問,派生類和其它類不能訪問。
繼承成員的訪問控制規則
——由父類成員的訪問控制方式和繼承訪問控制方式共同決定
private+public(protectd,private)=>不可訪問
pubic(protected)+public=>public(protected)
public(protected)+protected=>protected
public(protected)+private(預設)=>private
C++中的模板和virtual異同? ==>?
private繼承和public繼承區別? ==>?
24:什麼是記憶體洩露?C++記憶體洩漏檢測記憶體洩露是指程式中動態分配了記憶體,但是在程式結束時沒有釋放這部分記憶體,從而造成那一部分記憶體不可用的情況
有一些記憶體洩漏的檢測工具,比如BoundsChecker。
靜態記憶體洩漏通過工具或者仔細檢查程式碼找到洩漏點。
動態的記憶體洩漏很難查,一般通過在程式碼中加斷點跟蹤和Run-Time記憶體檢測工具來查詢。
記憶體洩漏的檢測可以分以下幾個步驟:
(1)看程式碼new之後是否delete,就是申請了靜態記憶體用完是否釋放。看解構函式是否真的執行,如果沒有真正執行,就需要動態釋放物件;
(2)讓程式長時間執行,看工作管理員對應程式記憶體是不是一直向上增加;
(3)使用常用記憶體洩漏檢測工具來檢測記憶體洩漏點。
25:標頭檔案的作用是什麼?
(1)標頭檔案用於儲存程式的宣告。
(2)通過標頭檔案可以來呼叫庫函式。因為有些程式碼不能向使用者公佈,只要向使用者提供標頭檔案和二進位制的庫即可。使用者只需要按照標頭檔案中的介面宣告來呼叫庫功能,編譯器會從庫中提取相應的程式碼。
(3)如果某個介面被實現或被使用時,其方式與標頭檔案中的宣告不一致,編譯器就會指出錯誤,這一簡單的規則能大大減輕程式設計師除錯、改錯的負擔。
26:函式模板與類别範本有什麼區別?
答:函式模板的例項化是由編譯程式在處理函式呼叫時自動完成的,而類别範本的例項化必須由程式設計師在程式中顯式地指定。
函式模板是模板的一種,可以生成各種型別的函式例項:
template
Type min( Type a, Type b )
{
return a < b ? a : b;
}
引數一般分為型別引數和非型別引數:
型別引數代表了一種具體的型別
非型別引數代表了一個常量表示式
27:system(”pause”)的作用?
呼叫DOS的命令,按任意鍵繼續,和getchar()差不多;省去了使用getchar();區別是一個屬於系統命令,一個屬於c++標準函式庫。
28:解構函式和虛擬函式的用法和作用?
解構函式是類成員函式,在類物件生命期結束的時候,由系統自動呼叫,釋放在建構函式中分配的資源。
虛擬函式是為了實現多型。含有純虛擬函式的類稱為抽象類,不能例項化物件,主要用作介面類
Test(int j):pb(j),pa(pb+5)
{
}
~Test()
{
cout<<“釋放堆區director記憶體空間1次”;
}
解構函式的特點:
1. 函式名稱固定:~類名( )
2. 沒有返回型別,沒有引數
3. 不可以過載,一般由系統自動的呼叫
29:編寫一個標準strcpy函式
可以拿10
char * strcpy( char *strDest, const char *strSrc )//為了實現鏈式操作,將目的地址返回,加3分!
{
assert( (strDest != NULL) &&(strSrc != NULL) );
char *address = strDest;
while( (*strDest++ = * strSrc++) != ‘ ’ );
return address;
}
30:new、delete;malloc、free關係
new和delete是一組,new用呼叫建構函式來例項化物件和呼叫解構函式釋放物件申請的資源。
malloc和free是一對,malloc用來申請記憶體和釋放記憶體,但是申請和釋放的物件只能是內部資料型別。
區別:
malloc與free是C++/C語言的標準庫函式,new/delete是C++的運算子。
maloc/free只能操作內部資料型別。
31:delete與 delete []區別
都是用來呼叫解構函式的:
(1)delete只會呼叫一次解構函式,delete[]會呼叫每一個成員的解構函式。
(2)delete與new配套,delete []與new []配套,用new分配的記憶體用delete刪除用new[]分配的記憶體用delete[]刪除
32:繼承優缺點
優點:
繼承可以方便地改變父類的實現,可以實現多型,子類可以繼承父類的方法和屬性。
缺點:
破壞封裝,子類和父類可能存在耦合。
子類不能改變父類的介面。
33:C和C++有什麼不同?
(1)c是程式導向的,也就是說更偏向邏輯設計;c++是物件導向的,提供了類,偏向類的設計。
(2)c適合要求程式碼體積小的,效率高的場合,如比如嵌入式。
34:解構函式的呼叫次序,子類析構時要呼叫父類的解構函式嗎?
解構函式呼叫的次序是:先派生類的析構後基類的析構,也就是說在基類的的析構呼叫的時候,派生類的資訊已經全部銷燬了定義一個物件時先呼叫基類的建構函式、然後呼叫派生類的建構函式;35:什麼是“野指標”?野指標指向一個已刪除的物件或無意義地址的指標。與空指標不同,野指標無法通過簡單地判斷是否為 NULL避免,而只能通過養成良好的程式設計習慣來盡力避免。造成的主要原因是:指標變數沒有被初始化,或者指標p被free或者delete之後,沒有置為NULL。36:常量指標和指標常量的區別?常量指標:是一個指向常量的指標。可以防止對指標誤操作而修改該常量。
指標常量:是一個常量,且是一個指標。指標常量不能修改指標所指向的地址,一旦初始化,地址就固定了,不能對它進行移動操作。但是指標常量的內容是可以改變。
37:sizeof的概念(作用),舉例
sizeof是C語言的一種單目操作符,並不是函式。sizeof以位元組的形式返回運算元的大小。
(1)sizeof(int **a[3][4])
int **p; //16位下sizeof(p)=2, 32位下sizeof(p)=4
總共 3*4*sizeof(p)
(2)若運算元具有型別char、unsigned char或signed char,其結果等於1。
(3)當運算元是指標時,sizeof依賴於系統的位數
(4)當運算元具有陣列型別時,其結果是陣列的總位元組數。
(5)聯合型別運算元的sizeof是其最大位元組成員的位元組數。
結構型別運算元的sizeof是這種型別物件的總位元組數(考慮對齊問題時)。這樣做可以提高程式的效能,避免訪問兩次記憶體;
(6)如果運算元是函式中的陣列形參或函式型別的形參,sizeof給出其指標的大小。
sizeof和strlen()的區別:① sizeof是運算子,計算資料所佔的記憶體空間;strlen()是一個函式,計算字元陣列的字元數;
② sizeof可以用型別作引數;strlen()只能用char*作引數,必須是以‘/0’結束
③ 陣列做sizeof的引數不退化,傳遞給strlen就退化為指標了;
④ sizeof操作符的結果型別是size_t,它在標頭檔案中typedef為unsigned int型別。該型別保證能容納實現建立的最大物件的位元組大小。
38:如果NULL 和0 作為空指標常數是等價的, 那到底該用哪一個?
#define NULL 0
按道理說,null和0,沒有區別,但為何要多此一舉呢,
(1)什麼是空指標常量?
0、0L、` `、3 – 3、0 * 17 以及 (void*)0都是空指標常量。
(2)什麼是空指標?
如果 p 是一個指標變數,則 p = 0;、p = 0L;、p = ` `;、p = 3 – 3;、p = 0 * 17; 中的任何一種賦值操作之後, p 都成為一個空指標,由系統保證空指標不指向任何實際的物件或者函式。
(3)什麼是 NULL?
即 NULL 是一個標準規定的巨集定義,用來表示空指標常量。因此,除了上面的各種賦值方式之外,還可以用 p = NULL; 來使 p 成為一個空指標。
(4)空指標指向了記憶體的什麼地方?
標準並沒有對空指標指向記憶體中的什麼地方這一個問題作出規定,一般取決於系統的實現。我們常見的空指標一般指向 0 地址,即空指標的內部用全 0 來表示。
空指標的“邏輯地址”一定是0,對於空指標的地址,作業系統是特殊處理的。並非空指標指向一個0地址的實體地址。
在實際程式設計中不需要了解在我們的系統上空指標到底是一個 0指標還是非0地址,我們只需要瞭解一個指標是否是空指標就可以了——編譯器會自動實現其中的轉換,為我們遮蔽其中的實現細節。
(5)可以用 memset 函式來得到一個空指標嗎?
這個問題等同於:如果 p 是一個指標變數,那麼memset( &p, 0, sizeof(p) ); 和 p = 0;是等價的嗎?
答案是否定的,雖然在大多數系統上是等價的,但是因為有的系統存在著“非零空指標” (nonzero null pointer),所以這時兩者不等價。
(6)可以定義自己的 NULL 的實現嗎?兼答”NULL 的值可以是 1、2、3 等值嗎?”類似問題
NULL 是標準庫中的一個符合上述條件的保留識別符號。所以,如果包含了相應的標準標頭檔案而引入了 NULL 的話,則再在程式中重新定義 NULL 為不同的內容是非法的,其行為是未定義的。也就是說,如果是符合標準的程式,其 NULL 的值只能是 0,不可能是除 0 之外的其它值,比如 1、2、3 等。
(7)malloc 函式在分配記憶體失敗時返回 0 還是 NULL?
malloc 函式是標準 C 規定的庫函式。在標準中明確規定了在其記憶體分配失敗時返回的是空指標
39:如果NULL定義成#define NULL ((char *)0) 難道不就可以向函式傳入不加轉換的NULL了嗎?
不行。因為有的機器不同型別資料的指標有不同的內部表達。如果是字元指標的函式沒有問題, 但對於其它型別的指標引數仍然有問題, 而合法的構造如FILE *fp = NULL;則會失敗。
如果定義#define NULL ((void *)0)除了潛在地幫助錯誤程式執行以外, 這樣的定義還可以發現錯誤使用NULL 的程式。無論如何, ANSI 函式原型確保大多數指標引數在傳入函式時正確轉換。
40:使用非全零的值作為空指標內部表達的機器上, NULL是如何定義的?
跟其它機器一樣: 定義為0 。當程式設計師請求一個空指標時, 無論寫“0” 還是“NULL”, 都是有編譯器來生成適合機器的空指標的二進位制表達形式。因此, 在空指標的內部表達不為0 的機器上定義NULL 為0 跟在其它機器上一樣合法:編譯器在指標上下文看到的未加修飾的0 都會被生成正確的空指標。
41:NULL 是什麼, 它是怎麼定義的?
很多人不願意在程式中到處出現未加修飾的0。因此定義了預處理巨集NULL為空指標常數, 通常是0 或者((void *)0) 。希望區別整數0 和空指標0 的人可以在需要空指標的地方使用NULL。
42:用“if(p)” 判斷空指標是否可靠?如果空指標的內部表達不是0 會怎麼樣?
表示式中要求布林值時:如果表示式等於0 則認為該值為假。if(p) 等價於if(p != 0)。
43:怎樣在程式裡獲得一個空指標?
在指標上下文中的常數0 會在編譯時轉換為空指標。
char *p = 0;
if(p != 0)
44:空指標到底是什麼?
空指標表示“未分配” 或者“尚未指向任何地方” 的指標。
空指標在概念上不同於未初始化的指標。空指標可以確保不指向任何物件或函式; 而未初始化指標則可能指向任何地方。
45:我能否用void** 指標作為引數, 使函式按引用接受一般指標?
不可移植。C 中沒有一般的指標的指標型別。void* 可以用作一般指標只是因為當它和其它型別相互賦值的時候, 如果需要, 它可以自動轉換成其它型別; 但是, 如果試圖這樣轉換所指型別為void* 之外的型別的void** 指標時, 這個轉換不能完成。
46:我有一個char * 型指標剛好指向一些int 型變數, 我想跳過它們。 為什麼((int *)p)++; 不行?
型別轉換的實質“把這些二進位制位看作另一種型別, 並作相應的對待”; ((int *)p)++是一個轉換操作符, 根據定義它只能生成一個右值(rvalue)。而右值既不能賦值, 也不能用++ 自增。正確的做法:p = (char *)((int *)p + 1);
47:*p++ 自增p 還是p 所指向的變數?
*p++ 和*(p++) 等價。要自增p 指向的值, 使用(*p)++, 或者++*p。
48:我想宣告一個指標併為它分配一些空間,程式碼char *p; *p = malloc(10)的問題;
你所宣告的指標是p, 而不是*p, 當你操作指標本身時, 你只需要使用指標的名字即可:p = malloc(10);
49:int i=7; printf(“%d
”, i++ *i++);的值?
i++*i++=49
50:列舉和#define 有什麼不同?1):#define 是在預編譯階段進行簡單替換。列舉常量則是在編譯的時候確定其值。
2):一般在編譯器裡,可以除錯列舉常量,但是不能除錯巨集常量。
3):列舉可以一次定義大量相關的常量,而#define 巨集一次只能定義一個。
51:C++檔案編譯與執行的四個階段
第一階段:預處理階段。根據檔案中的預處理指令來修改原始檔的內容。如#include指令,作用是把標頭檔案的內容新增到.cpp檔案中。
第二階段:編譯階段,將其翻譯成等價的中間程式碼或彙編程式碼。
第三階段:彙編階段,把組合語言翻譯成目標機器指令。
第四階段:是連結,例如,某個原始檔中的函式可能引用了另一個原始檔中定義的某個函式;在程式中可能呼叫了某個庫檔案中的函式。
52:宣告struct x1 { . . . }; 和typedef struct { . . . } x2; 有什麼不同?
第一種形式宣告瞭一個“結構標籤”;
第二種宣告瞭一個“型別定義”。
主要的區別是第一種方式定義結構體變數需要寫“struct x1”而引用第一種, 而第二種方式定義結構體變數不需要使用struct 關鍵字。
53:以下的初始化有什麼區別?
char a[] = “string literal”; char *p= “string literal”
用作陣列初始值, 它指明該陣列中字元的初始值。
第二種情況會轉化為一個無名的靜態字元陣列, 可能會儲存在只讀記憶體中, 這就是造成它不一定能被修改。第二個宣告把p 初始化成指向無名陣列的第一個元素。為了編譯舊程式碼, 有的編譯器有一個控制字串是否可寫的開關。
54:對於沒有初始化的變數的初始值可以作怎樣的假定?如果一個全域性變數初始值為“零”, 它可否作為空指標或浮點零?
對於具有“靜態” 生存期的未初始化全域性變數可以確保初始值為零,如果是指標會被初始化為正確的空指標, 如果是浮點數會被初始化為0.0 。
對於區域性變數,如果沒有顯示地初始化, 則包含的是垃圾內容。
用malloc() 和realloc() 動態分配的記憶體也可能包含垃圾資料, 因此必須由呼叫者正確地初始化。
55:函式指標的定義是什麼?
是一個指向函式的指標。看例子:
A),char * (*fun1)(char * p1,char * p2);//fun1 不是函式名,而是一個指標變數,它指向一個函式。這個函式有兩個指標型別的引數,函式的返回值也是一個指針。
B),char * *fun2(char * p1,char * p2);//是個二級指標
C),char * fun3(char * p1,char * p2);//函式的返回值為char *型別
56:int *p = NULL 和*p = NULL 有什麼區別?
int *p = NULL;//定義一個指標變數p,其指向的記憶體裡面儲存的是int 型別的資料;在定義變數p 的同時把p 的值設定為0×00000000,而不是把*p 的值設定為0×00000000
int *p;
*p = NULL;
給*p 賦值為NULL,即給p指向的記憶體賦值為NULL;但是由於p 指向的記憶體可能是非法的,所以除錯的時候編譯器可
能會報告一個記憶體訪問錯誤。
int i = 10;
int *p = &i;
*p = NULL;
在編譯器上除錯一下,我們發現p 指向的記憶體由原來的10 變為0 了;而p 本身的值, 即記憶體地址並沒有改變。
57:介紹一下#error 預處理
#error 預處理指令的作用是,編譯程式時,只要遇到#error 就會生成一個編譯錯誤提示訊息,並停止編譯。其語法格式為:
#error error-message
注意,巨集串error-message 不用雙引號包圍。遇到#error 指令時,錯誤資訊被顯示,可能同時還顯示編譯程式作者預先定義的其他內容。
58:用變數a給出下面的定義
a) int a; //一個整型數
b) int *a; //一個指向整型數的指標
c) int **a; //一個指向指標的的指標,它指向的指標是指向一個整型數
d) int a[10]; //一個有10個整型數的陣列
e) int *a[10]; //一個有10個指標的陣列,該指標是指向一個整型數的
f) int (*a)[10]; //一個指向有10個整型數陣列的指標
g) int (*a)(int); //一個指向函式的指標,該函式有一個整型引數並返回一個整型數
h) int (*a[10])(int); // 一個有10個指標的陣列,該指標指向一個函式,該函式有一個整型引數並返回一個整型數
59:分別給出BOOL,int,float,指標變數 與“零值”比較的 if 語句(假設變數名為var)
BOOL型變數:if(!var)
int型變數: if(var==0)
float型變數:
const float EPSINON = 0.00001;
if ((x >= – EPSINON) && (x <= EPSINON)
指標變數: if(var==NULL)
60:什麼是預編譯?何時需要預編譯?預編譯又稱為預處理 , 是做些程式碼文字的替換工作。處理 # 開頭的指令 , 比如拷貝 #include 包含的檔案程式碼, #define 巨集定義的替換 , 條件編譯等。
c 編譯系統在對程式進行通常的編譯之前,先進行預處理。 c 提供的預處理功能主要有以下三 種: 1 )巨集定義 2 )檔案包含 3 )條件編譯
61:行內函數與巨集有什麼區別
行內函數在編譯時展開,巨集在預編譯時展開
在編譯的時候行內函數可以直接被嵌入到目的碼中,而巨集只是一個簡單的文字替換
行內函數可以完成諸如型別檢測、語句是否正確等編譯功能,巨集就不具備這樣的功能
inline函式是函式,巨集不是函式。
62:iostream與iostream.h的區別#include <iostream.h>非標準輸入輸出流
#include <iostream>標準輸入輸出流
有“.h”的就是非標準的,C的標準庫函式,無“.h”的,就要用到命令空間,是C++的。63:namespace的使用因為標準庫非常的龐大,所程式設計師在選擇的類的名稱或函式名時就很有可能和標準庫中的某個名字相同。所以為了避免這種情況所造成的名字衝突,就把標準庫中的一切都被放在名字空間std中。
C++標準程式庫中的所有識別符號都被定義於一個名為std的namespace中。
1、直接指定識別符號。例如std::ostream
2、使用using關鍵字。
using std::cout;
using std::endl;
3、最方便的就是使用using namespace std;
64:堆與棧的區別(1)一個是靜態的,一個是動態的,堆是靜態的,由使用者申請和釋放,棧是動態的,儲存程式的區域性變數(2)申請後系統的響應不同
棧:只要棧的剩餘空間大於申請空間,系統就為程式提供記憶體,否則將丟擲棧溢位異常
堆:當系統收到程式申請時,先遍歷作業系統中記錄空閒記憶體地址的連結串列,尋找第一個大於所申請空間的堆結點,然後將該結點從空間結點連結串列中刪除,並將該結點的空間分配給程式。
(3)申請大小限制的不同
棧:在windows下,棧的大小一般是2M,如果申請的空間超過棧的剩餘空間時,將提示overflow。
堆:堆是向高地址擴充套件的資料結構,是不連續的記憶體區域。這是由於系統是用連結串列來儲存的空閒記憶體地址的,自然是不連續的,而連結串列的遍歷方向是由低地址向高地址。堆的大小受限於計算機系統中有效的虛擬記憶體。由此可見,堆獲得的空間比較靈活,也比較大。
65:含引數的巨集與函式的優缺點
巨集: 優點:在預處理階段完成,不佔用編譯時間,同時,省去了函式呼叫的開銷,執行效率高
缺點:不進行型別檢查,多次巨集替換會導致程式碼體積變大,而且由於巨集本質上是字串替換,故可能會由於一些引數的副作用導致得出錯誤的結果。
函式:優點:有型別檢查,比較安全。缺點:函式呼叫需要引數、返回地址等的入棧、出棧開銷,效率沒有帶引數巨集高
巨集與行內函數的區別
行內函數和巨集都是在程式出現的地方展開,行內函數不是通過函式呼叫實現的,是在呼叫該函式的程式處將它展開(在編譯期間完成的);巨集同樣是;
不同的是:行內函數可以在編譯期間完成諸如型別檢測,語句是否正確等編譯功能;巨集就不具有這樣的功能,而且巨集展開的時間和行內函數也是不同的(在執行期間展開)
66:多型的作用?
(1)可以隱藏實現的細節,使得程式碼模組化;方便擴充套件程式碼;
(2)可以實現介面重用。
67: 類的靜態成員和非靜態成員有何區別?
靜態成員則是屬於這個類的非靜態成員是屬於每個物件的
68:C++純虛擬函式,虛擬函式,虛擬函式的實現,什麼是虛指標?
純虛擬函式是在基類中宣告的虛擬函式,它在基類中沒有定義,但要求任何派生類都要定義自己的實現方法。
virtual void f()=0;//是一個介面,子類必須實現這個介面虛指標或虛擬函式指標是虛擬函式的實現細節。帶有虛擬函式的每一個物件都有一個虛指標指向該類的虛擬函式表。虛擬函式 :虛擬函式是在基類中被宣告為virtual,並在派生類中重新定義的成員函式,可實現成員函式的動態覆蓋(Override)
純虛擬函式和虛擬函式的區別是,純虛擬函式子類必須實現。
純虛擬函式的優點:(1)可以實現多型特性
(2)定義一個標準的介面,在派生類中必須予以重寫以實現多型性。
抽象類 :包含純虛擬函式的類稱為抽象類。由於抽象類包含了沒有定義的純虛擬函式,所以不能定義抽象類的物件。
多型性可分為兩類:靜態多型和動態多型。函式過載和運算子過載實現的多型屬於靜態多型,動態多型性是通過虛擬函式實現的。
虛擬函式與建構函式,解構函式,成員函式的關係
為什麼基類解構函式是虛擬函式?
編譯器總是根據型別來呼叫類成員函式。但是一個派生類的指標可以安全地轉化為一個基類的指標。這樣刪除一個基類的指標的時候,C++不管這個指標指向一個基類物件還是一個派生類的物件,呼叫的都是基類的解構函式而不是派生類的。如果你依賴於派生類的解構函式的程式碼來釋放資源,而沒有過載解構函式,那麼會有資源洩漏。
為什麼建構函式不能為虛擬函式
虛擬函式採用一種虛呼叫的方法。需呼叫是一種可以在只有部分資訊的情況下工作的機制。如果建立一個物件,則需要知道物件的準確型別,因此建構函式不能為虛擬函式。
如果虛擬函式是有效的,那為什麼不把所有函式設為虛擬函式?
不行。因為每個虛擬函式的物件都要維護一個虛擬函式表,因此在使用虛擬函式的時候都會產生一定的系統開銷,這是沒有必要的。
69:物件導向的三個基本特徵,並簡單敘述之?
1. 封裝:將客觀事物抽象成類,每個類對自身的資料和方法。封裝可以使得程式碼模組化,目的是為了程式碼重用
2. 繼承:子類繼承父類的方法和屬性,繼承可以擴充套件已存在的程式碼,目的是為了程式碼重用
3. 多型:允許將子類型別的指標賦值給父類型別的指標。
70:什麼是“&(引用)”?申明和使用“引用”要注意哪些問題?
引用就是某個目標變數的“別名”。注意事項:(1)申明一個引用的時候,必須要對其進行初始化。(2)初始化後,該引用名不能再作為其他變數名的別名。(3)引用本身不佔儲存單元,系統不給引用分配儲存單元。(4)返回引用時,在記憶體中不產生被返回值的副本
(5)不能返回區域性變數的引用。主要原因是區域性變數會在函式返回後被銷燬.
71:引用與多型的關係?
引用就是物件的別名。引用主要用作函式的形參。引用必須用與該引用同型別的物件初始化: 引用是除指標外另一個可以產生多型效果的手段。這意味著,一個基類的引用可以指向它的派生類例項。
int ival = 1024;int &refVal = ival;
const 物件的引用只能是const型別的:const int ival = 1024;const int &refVal = ival;
多型是通過虛擬函式實現的。
72:指標和引用有什麼區別;為什麼傳引用比傳指標安全?如果我使用常量指標難道不行嗎?
(1) 引用在建立的同時必須初始化,保證引用的物件是有效的,所以不存在NULL引用;而指標在定義的時候不必初始化,所以,指標則可以是NULL,可以在定義後面的任何地方重新賦值。
(2) 引用一旦被初始化為指向一個物件,它就不能被改變為另一個物件的引用;而指標在任何時候都可以改變為指向另一個物件.
(3) 引用的建立和銷燬並不會呼叫類的拷貝建構函式
因為不存在空引用,並且引用一旦被初始化為指向一個物件,它就不能被改變為另一個物件的引用,所以比指標安全。
由於const 指標仍然存在空指標,並且有可能產生野指標,所以還是不安全
73:引數傳遞有幾種方式;實現多型引數傳遞採用什麼方式,如果沒有使用某種方式原因是什麼?
傳值,傳指標或者引用
74:拷貝建構函式相關問題,深拷貝,淺拷貝,臨時物件等。
深拷貝意味著拷貝了資源和指標,而淺拷貝只是拷貝了指標,沒有拷貝資源
這樣使得兩個指標指向同一份資源,可能造成對同一份析構兩次,程式崩潰。而且浪費時間,並且不安全。
臨時物件的開銷比區域性物件小些。
75:建構函式的特點
建構函式只在建立物件的時候自動被呼叫一次
建構函式必須是公共的,否則無法生成物件
建構函式只負責為自己的類構造物件
在建構函式中初始化變數
Person::Person( ) : name(“Jack”), age(30)
{
…
}
76:物件導向如何實現資料隱藏
定義類來實現資料隱藏:
成員函式和屬性的型別:
私有成員private
保護成員protected
公共成員public
77:字元指標、浮點數指標、以及函式指標這三種型別的變數哪個佔用的記憶體最大?為什麼?
所有指標變數佔用記憶體單元的數量都是相同的。
78:C++是不是型別安全的?
不是。兩個不同型別的指標之間可以強制轉換.
79:const char*, char const*, char *const的區別是什麼?
把一個宣告從右向左讀,* 讀成指向
char * const cp;//cp是常指標,指向char型別的資料
const char * cp;//cp是char型別的指標,指向const char
char const * p;//C++裡面沒有const*的運算子,所以const屬於前面的型別。
80:什麼是模板和巨集?模板怎麼實現?模板有什麼缺點和優點?模版特化的概念,為什麼特化?
標準庫大量採用了模板技術。比如容器。
模板是一個藍圖,它本身不是類或函式。編譯器用模板產生指定的類或函式的特定型別版本。模版的形參分為型別形參和非型別形參型別形參就是表示型別的形參,跟在關鍵字typename後非型別形參用來表示常量表示式
81:空指標和懸垂指標的區別?
空指標是指被賦值為NULL的指標;delete指向動態分配物件的指標將會產生懸垂指標。
空指標可以被多次delete,而懸垂指標再次刪除時程式會變得非常不穩定;
使用空指標和懸垂指標都是非法的,而且有可能造成程式崩潰,如果指標是空指標,儘管同樣是崩潰,但和懸垂指標相比是一種可預料的崩潰。
(a)指標陣列和陣列指標,函式指標和指標函式相關概念
指標陣列:用於儲存指標的陣列
int* a[4]
元素表示:*a[i]
陣列指標:指向陣列的指標
int (*a)[4]
元素表示:(*a)[i]
指標函式:函式返回型別是某一型別的指標,int *f(x,y);
指標函式與函式指標表示方法的不同。最簡單的辨別方式就是看函式名前面的指標*號有沒有被括號()包含,如果被包含就是函式指標,反之則是指標函式。
函式指標:是指向函式的指標變數,即本質是一個指標變數。
int (*f) (int x); /* 宣告一個函式指標 */ 型別說明符 (*指標的變數名)(引數)
f=func; /* 將func函式的首地址賦給指標f */
指向函式的指標包含了函式的地址
指標的指標:
例如:char ** cp;
如果有三個星號,那就是指標的指標的指標,依次類推。
指標的指標需要用到指標的地址。
char c=`A`;
char *p=&c;
char **cp=&p;
通過指標的指標,不僅可以訪問它指向的指標,還可以訪問它指向的指標所指向的資料:
char *p1=*cp;
char c1=**cp;
指向指標陣列的指標:
char *Names[]={ Bill,Sam,0};
char **nm=Names;
while(*nm!=0) printf(%s
,*nm++);
先用字元型指標陣列Names的地址來初始化指標nm。每次printf()的呼叫都首先傳遞指標nm指向的字元型指標,然後對nm進行自增運算使其指向陣列的下一個元素(還是指標)。
82:什麼是智慧指標?
當類中有指標成員時,一般有兩種方式來管理指標成員:
(1)每個類物件都保留一份指標指向的物件的拷貝;
(2)使用智慧指標,從而實現指標指向的物件的共享。實質是使用計數器與物件相關聯,這樣做可以保證物件正確的刪除,避免垂懸指標。
每次建立類的新物件時,初始化指標並將引用計數置為1;當物件作為另一物件的副本而建立時,拷貝建構函式拷貝指標並增加與之相應的引用計數;對一個物件進行賦值時,賦值操作符減少左運算元所指物件的引用計數,並增加右運算元所指物件的引用計數;呼叫解構函式時,建構函式減少引用計數。
83:C++空類預設有哪些成員函式?
預設建構函式、解構函式、複製建構函式、賦值函式
84:哪一種成員變數可以在一個類的例項之間共享?
答:static靜態成員變數
85:什麼是多型?多型有什麼作用?如何實現的?多型的缺點?
多型就是一個介面,多種方法。所以說,多型的目的則是為了實現介面重用。也就是說,不論傳遞過來的究竟是那個類的物件,函式都能夠通過同一個介面呼叫到適應各自物件的實現方法。
C++的多型性是通過虛擬函式來實現的,虛擬函式允許子類重新定義成員函式,而子類重新定義父類的做法稱為覆蓋(override),或重寫。而過載則是允許有多個同名的函式,而這些函式的引數列表不同,允許引數個數不同,引數型別不同。編譯器會根據函式列表的不同,而生成一些不同名稱的預處理函式,來實現同名函式的過載。但這並沒有體現多型性。
多型與非多型的實質區別就是函式的地址是執行時確定還是編譯時確定。如果函式的呼叫在編譯器編譯期間就可以確定函式的呼叫地址,並生產程式碼,是靜態的。而如果函式呼叫的地址在執行時才確定,就是動態的。
最常見的用法就是宣告基類的指標,利用該指標指向任意一個子類物件,呼叫相應的虛擬函式,可以根據指向的子類的不同而實現不同的方法。如果沒有使用虛擬函式的話,即沒有利用C++多型性,則利用基類指標呼叫相應的函式的時候,將總被限制在基類函式本身,而無法呼叫到子類中被重寫過的函式
86:虛擬函式表解析和記憶體佈局
虛擬函式表
虛擬函式是通過一張虛擬函式表來實現的。就像一個地圖一樣,指明瞭實際所應該呼叫的函式的地址。
這裡我們著重看一下這張虛擬函式表。C++的編譯器保證了虛擬函式表的指標存在於物件例項中最前面的位置(為了效能)。因此我們可以通過物件例項的地址得到這張虛擬函式表,然後通過遍歷其中函式指標,並呼叫相應的函式。
為什麼可以由父類的指標呼叫子類的物件的虛擬函式:
Derive d;//Derive 是Base的子類
Base *b1 = &d;//這必須使用父類的指標???
b1->f(); //Derive::f()
87:公有繼承、受保護繼承、私有繼承
1)公有繼承時,派生類物件可以訪問基類中的公有成員,派生類的成員函式可以訪問基類中的公有和受保護成員;公有繼承時基類受保護的成員,可以通過派生類物件訪問但不能修改。
2)私有繼承時,基類的成員只能被直接派生類的成員訪問,無法再往下繼承;
3)受保護繼承時,基類的成員也只被直接派生類的成員訪問,無法再往下繼承。
88:有哪幾種情況只能用建構函式初始化列表而不能用賦值初始化?
答:const成員,引用成員
89:C++如何阻止一個類被例項化?一般在什麼時候將建構函式宣告為private?
1)將類定義為抽象基類或者將建構函式宣告為private;
2)不允許類外部建立類物件,只能在類內部建立物件
90:類使用static成員的優點,如何訪問?
(1)static 成員的名字是在類的作用域中,因此可以避免與其他類的成員或全域性物件名字衝突;
(2)可以實施封裝。static 成員可以是私有成員,而全域性物件不可以;
(3) static 成員是與特定類關聯的,可清晰地顯示程式設計師的意圖。
91:static資料成員和static成員函式
(1)static資料成員:
static資料成員獨立於該類的任意物件而存在;static資料成員(const static資料成員除外)在類定義體內宣告,必須在類外進行初始化。不像普通資料成員,static成員不能在類的定義體中初始化,只能在定義時才初始化。 static資料成員定義放在cpp檔案中,不能放在初始化列表中。Const static成員可就地初始化。
變數定義:用於為變數分配儲存空間,還可為變數指定初始值。程式中,變數有且僅有一個定義。
變數宣告:用於向程式表明變數的型別和名字。
(2)static成員函式:
在類的外部定義,Static成員函式沒有this形參,它可以直接訪問所屬類的static成員,不能直接使用非static成員。因為static成員不是任何物件的組成部分,所以static成員函式不能被宣告為const。同時,static成員函式也不能被宣告為虛擬函式。
92:C++的內部連線和外部連線
編譯單元:當編譯cpp檔案時,前處理器首先遞迴包含標頭檔案,形成一個編譯單元。這個編譯單元會被編譯成為一個與cpp檔名同名的目標檔案(.o或是.obj)。連線程式把不同編譯單元中產生的符號聯絡起來,構成一個可執行程式。
內部連線:如果一個名稱對於它的編譯單元來說是區域性的,並且在連線時不會與其它編譯單元中的同樣的名稱相沖突,那麼這個名稱有內部連線:
a)所有的宣告
b)名字空間(包括全域性名字空間)中的靜態自由函式、靜態友元函式、靜態變數的定義
c)enum定義
d)inline函式定義(包括自由函式和非自由函式)
e)類的定義
f)名字空間中const常量定義
g)union的定義
外部連線:在一個多檔案程式中,如果一個名稱在連線時可以和其它編譯單元互動,那麼這個名稱就有外部連線。
以下情況有外部連線:
a)類非inline函式總有外部連線。包括類成員函式和類靜態成員函式
b)類靜態成員變數總有外部連線。
c)名字空間(包括全域性名字空間)中非靜態自由函式、非靜態友元函式及非靜態變數
93:變數的分類,全域性變數和區域性變數有什麼區別?實怎麼實現的?作業系統和編譯器是怎麼知道的?static全域性變數與普通的全域性變數有什麼區別?static區域性變數和普通區域性變數有什麼區別?static函式與普通函式有什麼區別?
1)變數可以分為:全域性變數、區域性變數、靜態全域性變數、靜態區域性變數
全域性變數在整個工程檔案內都有效;靜態全域性變數只在定義它的檔案內有效區域性變數在定義它的函式內有效,這個函式返回會後失效。
靜態區域性變數只在定義它的函式內有效,只是程式僅分配一次記憶體,函式返回後,該變數不會消失,直到程式執行結束後才釋放;全域性變數和靜態變數如果沒有手工初始化,則由編譯器初始化為0。區域性變數的值不可知。
靜態全域性變數是定義儲存型別為靜態型的外部變數,其作用域是從定義點到程式結束,所不同的是儲存型別決定了儲存地點,靜態型變數是存放在記憶體的資料區中的,它們在程式開始執行前就分配了固定的位元組,在程式執行過程中被分配的位元組大小是不改變的.只有程式執行結束後,才釋放所佔用的記憶體.
變數的作用域:
形參變數只在被呼叫期間才分配記憶體單元,呼叫結束立即釋放。 這一點表明形參變數只有在函式內才是有效的, 離開該函式就不能再使用了。區域性變數也稱為內部變數。其作用域僅限於函式內, 離開該函式後再使用這種變數是非法的。
全域性變數也稱為外部變數,它不屬於哪一個函式,它屬於一個源程式檔案。其作用域是整個源程式。在函式中使用全域性變數,一般應作全域性變數說明。 只有在函式內經過說明的全域性變數才能使用。全域性變數的說明符為extern。 但在一個函式之前定義的全域性變數,在該函式內使用可不再加以說明。
對於全域性變數還有以下幾點說明:
外部變數可加強函式模組之間的資料聯絡, 但是又使函式要依賴這些變數,因而使得函式的獨立性降低。從模組化程式設計的觀點來看這是不利的, 因此在不必要時儘量不要使用全域性變數。
在同一原始檔中,允許全域性變數和區域性變數同名。在區域性變數的作用域內,全域性變數不起作用。
變數的儲存方式可分為“靜態儲存”和“動態儲存”兩種。
靜態儲存變數通常是在變數定義時就分定儲存單元並一直保持不變, 直至整個程式結束。動態儲存變數是在程式執行過程中,使用它時才分配儲存單元, 使用完畢立即釋放。 如果一個函式被多次呼叫,則反覆地分配、 釋放形參變數的儲存單元。從以上分析可知, 靜態儲存變數是一直存在的, 而動態儲存變數則時而存在時而消失。我們又把這種由於變數儲存方式不同而產生的特性稱變數的生存期。 生存期表示了變數存在的時間。 生存期和作用域是從時間和空間這兩個不同的角度來描述變數的特性,這兩者既有聯絡,又有區別。 一個變數究竟屬於哪一種儲存方式, 並不能僅從其作用域來判斷,還應有明確的儲存型別說明。
從作用域看:
全域性變數具有全域性作用域。全域性變數只需在一個原始檔中定義,就可以作用於所有的原始檔。當然,其他不包含全域性變數定義的原始檔需要用extern 關鍵字再次宣告這個全域性變數。
靜態區域性變數具有區域性作用域,它只被初始化一次,自從第一次被初始化直到程式執行結束都一直存在,它和全域性變數的區別在於全域性變數對所有的函式都是可見的,而靜態區域性變數只對定義自己的函式體始終可見。
區域性變數也只有區域性作用域,它是自動物件(auto),它在程式執行期間不是一直存在,而是隻在函式執行期間存在,函式的一次呼叫執行結束後,變數被撤銷,其所佔用的記憶體也被收回。
靜態全域性變數也具有全域性作用域,它與全域性變數的區別在於如果程式包含多個檔案的話,它作用於定義它的檔案裡,不能作用到其它檔案裡,即被static關鍵字修飾過的變數具有檔案作用域。這樣即使兩個不同的原始檔都定義了相同名字的靜態全域性變數,它們也是不同的變數。
從分配記憶體空間看:
全域性變數,靜態區域性變數,靜態全域性變數都在靜態儲存區分配空間,而區域性變數在棧裡分配空間。
全域性變數本身就是靜態儲存方式,靜態全域性變數當然也是靜態儲存方式。這兩者在儲存方式上並無不同。這兩者的區別雖在於非靜態全域性變數的作用域是整個源程式,當一個源程式由多個原始檔組成時,非靜態的全域性變數在各個原始檔中都是有效的。而靜態全域性變數則限制了其作用域,即只在定義該變數的原始檔內有效,在同一源程式的其它原始檔中不能使用它。由於靜態全域性變數的作用域侷限於一個原始檔內,只能為該原始檔內的函式公用,因此可以避免在其它原始檔中引起錯誤。
1)、靜態變數會被放在程式的靜態資料儲存區(全域性可見)中,這樣可以在下一次呼叫的時候還可以保持原來的賦值。這一點是它與堆疊變數和堆變數的區別。
2)、變數用static告知編譯器,自己僅僅在變數的作用範圍內可見。這一點是它與全域性變數的區別。
程式的區域性變數存在於(堆疊)中,全域性變數存在於(靜態區 )中,動態申請資料存在於( 堆)中。
94:應用程式在執行時的記憶體包括程式碼區和資料區,其中資料區又包括哪些部分?
對於一個程式的記憶體空間而言,可以在邏輯上分成 3個部份:程式碼區,靜態資料區和動態資料區。
動態資料區一般就是“堆疊”。 棧是一種線性結構,堆是一種鏈式結構。程式的每個執行緒都有私有的“棧”。
全域性變數和靜態變數分配在靜態資料區,本地變數分配在動態資料區,即堆疊中。程式通過堆疊的基地址和偏移量來訪問本地變數。
95:C++裡面是不是所有的動作都是main()引起的?如果不是,請舉例。
比如全域性變數的初始化,就不是由main函式引起的:
class A{};
A a; //a的建構函式限執行
int main() {}
96:異常框架
異常存在於程式的正常功能之外,並要求程式立即處理。 C++ 的異常處理包括: 1. throw 表示式,錯誤檢測部分使用這種表示式來說明遇到了不可處理的錯誤。2. try 塊,錯誤處理部分使用它來處理異常。try 語句塊以 try 關鍵字開 始,並以一個或多個 catch 子句結束。在 try 塊中執行的程式碼所丟擲 (throw)的異常,通常會被其中一個 catch 子句處理。3. 由標準庫定義的一組異常類,用來在 throw 和相應的 catch 之間傳遞有關的錯誤資訊。 throw 表示式:if (!item1.same_isbn(item2))throw runtime_error(“Data must refer to same ISBN”);
try 塊:try {program-statements} catch (exception-specifier) {handler-statements} catch (exception-specifier) {handler-statements}
函式在尋找處理程式碼的過程中退出在複雜的系統中,程式的執行路徑也許在遇到丟擲異常的程式碼之前,就已經經過了多個 try 塊。丟擲一個異常時,首先要搜尋 的是丟擲異常的函式。如果沒有找到匹配的 catch,則終止這個函式的執行,並在呼叫這個函式的函式中尋找相配的 catch。如果仍然沒有找到相應的處理程式碼,該函式同樣要終止,搜尋呼叫它的函式。直到找到適當型別的 catch 為止。
相關文章
- 2019 Vue 面試題彙總(持續更新中...)Vue面試題
- PHP面試題總結-持續更新中PHP面試題
- 2020年騰訊實習生C++面試題&持續更新中(3)C++面試題
- 前端面試經典題目彙總(持續更新中)前端面試
- 總結Java開發面試常問的問題,持續更新中~Java面試
- Spring面試題(持續更新中)Spring面試題
- 【前端面試】Vue面試題總結(持續更新中)前端Vue面試題
- C++常見的面試題目整理C++面試題
- JavaScript常見面試題彙總(含答案)JavaScript面試題
- Java常見面試題及答案彙總Java面試題
- 【彙總】Python爬蟲常見面試題!Python爬蟲面試題
- AI面試題(持續更新)AI面試題
- Hbase面試題(持續更新)面試題
- LeetCode Animation 題目圖解彙總(持續更新中...)LeetCode圖解
- 常見 git 需求整理(持續更新中)Git
- C++知識點 —— 整合(持續更新中)C++
- LeetCode刷題:數學篇(C++實現,持續更新中...)LeetCodeC++
- 前端面試題總結——HTML(持續更新中)前端面試題HTML
- 2020年前端常見面試題解析彙總前端面試題
- LeetCode刷題:設計問題篇(C++實現,持續更新中...)LeetCodeC++
- 【彙總】網路安全滲透測試常見面試題!面試題
- 面試寶典:15道MyBatis 常見面試題彙總及答案MyBatis面試題
- python 系列文章彙總(持續更新…)Python
- C++關鍵字(持續更新ing)C++
- 前端面試題總結——綜合問題(持續更新中)前端面試題
- c++ 常見問題C++
- C++連結串列常見面試考點C++面試
- GO面試題集錦快答[持續更新]Go面試題
- 前端面試題總結——Html5(持續更新中)前端面試題HTML
- 2024-04-19 前端常見面試題彙總(vue篇)前端面試題Vue
- 2024-04-19 前端常見面試題彙總(react篇)前端面試題React
- Unity打包安卓專案問題彙總(持續更新)Unity安卓
- 彙編筆記(持續更新中)筆記
- Webpack常見面試題總結Web面試題
- 資料分析面試|SQL真題持續更新面試SQL
- 京東前端二面高頻手寫面試題(持續更新中)前端面試題
- 【LinuxSRE運維學習】2022最新Docker常見面試題彙總!Linux運維Docker面試題
- 國產資料庫考試資料彙總(持續更新)資料庫
- 前端演算法類面試總結(持續更新...)前端演算法面試