while循环中指针会自动释放吗_C++】C++常见面试题汇总_持续更新中...
1:指針(*)、引用(&)、解引用(*)、取地址(&)、的概念和區(qū)別
概念:
指針指向一塊內(nèi)存,指針保存的是內(nèi)存的地址;引用是變量的別名,本質(zhì)是引用該變量的地址。
解引用是取指針指向的地址的內(nèi)容,取地址是獲得變量在內(nèi)存中的地址。
區(qū)別:
1引用使用是無需解引用,指針需解引用。
(2)引用不能為空,指針可以為空。
(3)引用在定義時被初始化一次,之后不可變;指針指向的值和本身的值是可變的,也就是說指針只是一塊地址,地址里的東西可變。
(4)程序會給指針變量分配內(nèi)存區(qū)域,而引用不需要分配內(nèi)存區(qū)域。
2:memset、memcpy和strcpy的區(qū)別
memcpy是內(nèi)存拷貝函數(shù),可以拷貝任何數(shù)據(jù)類型的對象,例如memcpy(b, a, sizeof(b))。
strcpy只能拷貝字符串,遇到’0′結(jié)束拷貝。
memset用來對一段內(nèi)存空間全部設(shè)置為某個字符,例如:char a[100];memset(a, '', sizeof(a))。
3:struct和class的區(qū)別,struct與union的區(qū)別
struct和class都是聲明類的關(guān)鍵字
區(qū)別是:
4:指針在16位機(jī)、32位機(jī)、64位機(jī)分別占用多少個字節(jié)
16位機(jī)--2字節(jié)、32位機(jī)--4字節(jié)、64位機(jī)--8字節(jié)。
5:如何引用一個已經(jīng)定義過的全局變量?區(qū)別是什么
如果在同一個文件中,直接引用即可。
如果不在同一個文件,有兩種方式:
(1)直接引用頭文件就可以使用了。
(2)用extern關(guān)鍵字重新聲明一下。
6:全局變量可不可以定義在可被多個.C文件包含的頭文件中?變量的聲明一般放在頭文件中,那么變的定義可以放在頭文件中嗎?在實(shí)際的編程中一般很少在頭文件中定義全局變量,因?yàn)槎啻我每赡苤囟x。7:do……while和while……do有什么區(qū)別?
do...while先執(zhí)行循環(huán)再判斷條件,while...do先判斷條件再執(zhí)行循環(huán)。
8:對于一個頻繁使用的短小函數(shù),在C語言中應(yīng)用什么實(shí)現(xiàn),在C++中應(yīng)用什么實(shí)現(xiàn)?
C用宏定義,C++用inline。9:main 函數(shù)執(zhí)行以前,會執(zhí)行什么代碼?
全局對象的構(gòu)造函數(shù)會在main 函數(shù)之前執(zhí)行,比如int a;初始化為0。
10:main 主函數(shù)執(zhí)行完畢后,會執(zhí)行什么代碼?
可以,使用on_exit 注冊的函數(shù)會在代碼執(zhí)行完畢后執(zhí)行:
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:描述內(nèi)存分配方式以及它們的區(qū)別?
1.從靜態(tài)存儲區(qū)域分配。該存儲區(qū)域在程序編譯的時候就已經(jīng)分配好了,這塊內(nèi)存在程序的整個運(yùn)行期間都存在。例如全局變量,static 變量。
2. 在棧上創(chuàng)建。在執(zhí)行函數(shù)時,函數(shù)的局部變量存儲在該區(qū)域,函數(shù)執(zhí)行結(jié)束時會釋放該存儲空間。棧內(nèi)存分配運(yùn)算內(nèi)置于處理器的指令集。
3. 從堆上分配,亦稱動態(tài)內(nèi)存分配。程序在運(yùn)行的時候用malloc 或new 申請任意多少的內(nèi)存,程序員自己負(fù)責(zé)在何時用free 或delete 釋放內(nèi)存。 動態(tài)內(nèi)存的生存期由程序員決定,使用非常靈活。
13:類的成員函數(shù)重載、覆蓋和隱藏的概念和區(qū)別?
14:static關(guān)鍵字?
15:const與#define的概念和優(yōu)缺點(diǎn)?
const用來定義常量、修飾函數(shù)返回值,可以避免被修改,提高程序的健壯性。
define是宏定義,在編譯的時候會進(jìn)行替換,這樣做的話可以避免沒有意義的數(shù)字或字符串,便于程序的閱讀。
區(qū)別:
1.const定義的數(shù)據(jù)有數(shù)據(jù)類型,而宏常量沒有數(shù)據(jù)類型。編譯器可以對const常量進(jìn)行類型檢查。而對宏定義只進(jìn)行字符替換,所以字符替換時可能出錯。
例子:
寫一個“標(biāo)準(zhǔn)”宏MIN,這個宏輸入兩個參數(shù)并返回較小的一個。
#define MIN(A,B) ((A) <= (B) (A) : (B))
least = MIN(a, b);
下面的關(guān)鍵字const是什么含意:
const int a;//a是一個常整型數(shù)
int const a;//a是一個常整型數(shù)
const int *a;//a是一個指向常整型數(shù)的指針
int * const a;//a是一個指向整型數(shù)的常指針
int const * a const;//a是一個指向常整型數(shù)的常指針
static關(guān)鍵字的作用:
(1)函數(shù)體內(nèi)static變量的作用范圍為該函數(shù)體,不同于auto變量,該變量的內(nèi)存只被分配一次,因此其值在下次調(diào)用時仍維持上 次的值;
(2)在模塊內(nèi)的static全局變量可以被模塊內(nèi)所用函數(shù)訪問,但不能被模塊外其它函數(shù)訪問;
(3)在模塊內(nèi)的static函數(shù)只可被這一模塊內(nèi)的其它函數(shù)調(diào)用,這個函數(shù)的使用范圍被限制在聲明它的模塊內(nèi);
(4)在類中的static成員變量屬于整個類所擁有,對類的所有對象只有一份拷貝;
(5)在類中的static成員函數(shù)屬于整個類所擁有,這個函數(shù)不接收this指針,因而只能訪問類的static成員變量。
const關(guān)鍵字的作用:
(1)欲阻止一個變量被改變,可以使用const關(guān)鍵字。在定義該const變量時,通常需要對它進(jìn)行初始化,因?yàn)橐院缶蜎]有機(jī)會再去改變它了;
(2)對指針來說,可以指定指針本身為const,也可以指定指針?biāo)傅臄?shù)據(jù)為const,或二者同時指定為const;
(3)在一個函數(shù)聲明中,const可以修飾形參,表明它是一個輸入?yún)?shù),在函數(shù)內(nèi)部不能改變其值;
(4)對于類的成員函數(shù),若指定其為const類型,則表明其是一個常函數(shù),不能修改類的成員變量;
(5)對于類的成員函數(shù),有時候必須指定其返回值為const類型,以使得其返回值不為“左值”。例如:
16:堆棧溢出的原因?
沒有回收垃圾資源
棧溢出:
例如局部變量數(shù)組越界訪問或者函數(shù)內(nèi)局部變量使用過多,超出了操作系統(tǒng)為該進(jìn)程分配的棧的大小。
堆溢出:
所以溢出的原因可能是程序員申請了資源但是忘記釋放了。
17:刷新緩沖區(qū)方式?
換行刷新緩沖區(qū):printf(“”);程序結(jié)束刷新緩沖區(qū):return 0;18:類和對象的兩個基本概念?類的作用或概念:用來描述一組具有相似屬性的東西的對象的一種數(shù)據(jù)結(jié)構(gòu)。類中有數(shù)據(jù)成員的聲明和定義,有成員函數(shù)的實(shí)現(xiàn)代碼。對象就是類的實(shí)例化。計(jì)算機(jī)中想要使用類,只能進(jìn)行實(shí)例化。
19:介紹一下STL,詳細(xì)說明STL如何實(shí)現(xiàn)vector。
STL是標(biāo)準(zhǔn)模版庫,由容器算法迭代器組成。
STL有以下的一些優(yōu)點(diǎn):
(1)可以很方便的對一堆數(shù)據(jù)進(jìn)行排序(調(diào)用sort());
(2)調(diào)試程序時更加安全和方便;
(3)stl是跨平臺的,在linux下也能使用。
vector實(shí)質(zhì)上就是一個動態(tài)數(shù)組,會根據(jù)數(shù)據(jù)的增加,動態(tài)的增加數(shù)組空間。
什么是容器。如何實(shí)現(xiàn)?
容器是一種類類型,用來存儲數(shù)據(jù)
STL有7種主要容器:vector,list,deque,map,multimap,set,multiset.
20:變量的聲明和定義有什么區(qū)別
變量的聲明是告訴編譯器我有某個類型的變量,但是定義會分配了內(nèi)存。
21:簡述#define #endif 和#ifndef的作用
這三個命令一般是為了避免頭文件被重復(fù)引用。
#ifndef CH_H //意思是如果沒有引用ch.h
#define CH_H //引用ch.h
#endif //否則不需要引用
22:引用與指針有什么區(qū)別?
(1) 引用必須被初始化,指針不必。
(2) 引用初始化以后不能被改變,指針可以改變所指的對象。
(3) 不存在指向空值的引用,但是存在指向空值的指針。
23:C++繼承機(jī)制?
n類成員的訪問控制方式
public:類本身、派生類和其它類均可訪問;
protected:類本身和派生類均可訪問,其它類不能訪問;
private(默認(rèn)):類本身可訪問,派生類和其它類不能訪問。
繼承成員的訪問控制規(guī)則
——由父類成員的訪問控制方式和繼承訪問控制方式共同決定
private+public(protectd,private)=>不可訪問
pubic(protected)+public=>public(protected)
public(protected)+protected=>protected
public(protected)+private(默認(rèn))=>private
C++中的模板和virtual異同? ==>?
private繼承和public繼承區(qū)別? ==>?
24:什么是內(nèi)存泄露?C++內(nèi)存泄漏檢測內(nèi)存泄露是指程序中動態(tài)分配了內(nèi)存,但是在程序結(jié)束時沒有釋放這部分內(nèi)存,從而造成那一部分內(nèi)存不可用的情況
有一些內(nèi)存泄漏的檢測工具,比如BoundsChecker。
靜態(tài)內(nèi)存泄漏通過工具或者仔細(xì)檢查代碼找到泄漏點(diǎn)。
動態(tài)的內(nèi)存泄漏很難查,一般通過在代碼中加斷點(diǎn)跟蹤和Run-Time內(nèi)存檢測工具來查找。
內(nèi)存泄漏的檢測可以分以下幾個步驟:
(1)看代碼new之后是否delete,就是申請了靜態(tài)內(nèi)存用完是否釋放。看析構(gòu)函數(shù)是否真的執(zhí)行,如果沒有真正執(zhí)行,就需要動態(tài)釋放對象;
(2)讓程序長時間運(yùn)行,看任務(wù)管理器對應(yīng)程序內(nèi)存是不是一直向上增加;
(3)使用常用內(nèi)存泄漏檢測工具來檢測內(nèi)存泄漏點(diǎn)。
25:頭文件的作用是什么?
(1)頭文件用于保存程序的聲明。
(2)通過頭文件可以來調(diào)用庫函數(shù)。只要向用戶提供頭文件和二進(jìn)制的庫即可。用戶只需要按照頭文件中的接口聲明來調(diào)用庫功能,編譯器會從庫中提取相應(yīng)的代碼。
(3)如果某個接口被實(shí)現(xiàn)或被使用時,其方式與頭文件中的聲明不一致,編譯器就會指出錯誤,這一簡單的規(guī)則能大大減輕程序員調(diào)試、
27:system(”pause”)的作用?
調(diào)用DOS的命令,按任意鍵繼續(xù),和getchar()差不多;省去了使用getchar();區(qū)別是一個屬于系統(tǒng)命令,一個屬于c++標(biāo)準(zhǔn)函數(shù)庫。
28:析構(gòu)函數(shù)和虛函數(shù)的用法和作用?
29:編寫一個標(biāo)準(zhǔn)strcpy函數(shù)
可以拿10
char * strcpy( char *strDest, const char *strSrc )//為了實(shí)現(xiàn)鏈?zhǔn)讲僮?#xff0c;將目的地址返回,加3分!
{
assert( (strDest != NULL) &&(strSrc != NULL) );
char *address = strDest;
while( (*strDest++ = * strSrc++) != ‘0’ );
return address;
}
30:new、delete;malloc、free關(guān)系
new和delete是一組,new用調(diào)用構(gòu)造函數(shù)來實(shí)例化對象和調(diào)用析構(gòu)函數(shù)釋放對象申請的資源。
malloc和free是一對,malloc用來申請內(nèi)存和釋放內(nèi)存,但是申請和釋放的對象只能是內(nèi)部數(shù)據(jù)類型。
區(qū)別:
malloc與free是C++/C語言的標(biāo)準(zhǔn)庫函數(shù),new/delete是C++的運(yùn)算符。
maloc/free只能操作內(nèi)部數(shù)據(jù)類型。
31:delete與 delete []區(qū)別 都是用來調(diào)用析構(gòu)函數(shù)的:
(1)delete只會調(diào)用一次析構(gòu)函數(shù),delete[]會調(diào)用每一個成員的析構(gòu)函數(shù)。
(2)delete與new配套,delete []與new []配套,用new分配的內(nèi)存用delete刪除用new[]分配的內(nèi)存用delete[]刪除
32:繼承優(yōu)缺點(diǎn) 優(yōu)點(diǎn):
繼承可以方便地改變父類的實(shí)現(xiàn),可以實(shí)現(xiàn)多態(tài),子類可以繼承父類的方法和屬性。
缺點(diǎn):
破壞封裝,子類和父類可能存在耦合。
子類不能改變父類的接口。
33:C和C++有什么不同?
(1)c是面向過程的,也就是說更偏向邏輯設(shè)計(jì);c++是面向?qū)ο蟮?#xff0c;提供了類,偏向類的設(shè)計(jì)。
(2)c適合要求代碼體積小的,效率高的場合,如比如嵌入式。
34:析構(gòu)函數(shù)的調(diào)用次序,子類析構(gòu)時要調(diào)用父類的析構(gòu)函數(shù)嗎?
也就是說在基類的的析構(gòu)調(diào)用的時候,派生類的信息已經(jīng)全部銷毀了定義一個對象時先調(diào)用基類的構(gòu)造函數(shù)、然后調(diào)用派生類的構(gòu)造函數(shù);
35:什么是“野指針”?野指針指向一個已刪除的對象或無意義地址的指針。與空指針不同,野指針無法通過簡單地判斷是否為 NULL避免,指針變量沒有被初始化,或者指針p被free或者delete之后,沒有置為NULL。
36:常量指針和指針常量的區(qū)別?常量指針:是一個指向常量的指針??梢苑乐箤χ羔樥`操作而修改該常量。
指針常量:是一個常量,且是一個指針。指針常量不能修改指針?biāo)赶虻牡刂?#xff0c;一旦初始化,地址就固定了,不能對它進(jìn)行移動操作。但是指針常量的內(nèi)容是可以改變。
37:sizeof的概念(作用),舉例
38:如果NULL 和0 作為空指針常數(shù)是等價的, 那到底該用哪一個?
#define NULL 0
按道理說,null和0,沒有區(qū)別,但為何要多此一舉呢,
(1)什么是空指針常量?
0、0L、'0'、3 - 3、0 * 17 以及 (void*)0都是空指針常量。
(2)什么是空指針?
如果 p 是一個指針變量,則 p = 0;、p = 0L;、p = '0';、p = 3 - 3;、p = 0 * 17; 中的任何一種賦值操作之后, p 都成為一個空指針,由系統(tǒng)保證空指針不指向任何實(shí)際的對象或者函數(shù)。
(3)什么是 NULL?
即 NULL 是一個標(biāo)準(zhǔn)規(guī)定的宏定義,用來表示空指針常量。因此,除了上面的各種賦值方式之外,還可以用 p = NULL; 來使 p 成為一個空指針。
(4)空指針指向了內(nèi)存的什么地方?
標(biāo)準(zhǔn)并沒有對空指針指向內(nèi)存中的這個問題作出規(guī)定,一般取決于系統(tǒng)的實(shí)現(xiàn)。我們常見的空指針一般指向 0 地址,即空指針的內(nèi)部用全 0 來表示。
空指針的“邏輯地址”一定是0,對于空指針的地址,操作系統(tǒng)是特殊處理的。并非空指針指向一個0地址的物理地址。
系統(tǒng)上空指針到底是一個 0指針還是非0地址,我們只需要了解一個指針是否是空指針就可以了——編譯器會自動實(shí)現(xiàn)其中的轉(zhuǎn)換,為我們屏蔽其中的實(shí)現(xiàn)細(xì)節(jié)。
(5)可以用 memset 函數(shù)來得到一個空指針嗎?
這個問題等同于:如果 p 是一個指針變量,那么memset( &p, 0, sizeof(p) ); 和 p = 0;是等價的嗎?
答案是否定的,雖然在大多數(shù)系統(tǒng)上是等價的,但是因?yàn)橛械南到y(tǒng)存在著“非零空指針” (nonzero null pointer),所以這時兩者不等價。
(6)可以定義自己的 NULL 的實(shí)現(xiàn)嗎?兼答"NULL 的值可以是 1、2、3 等值嗎?"類似問題
NULL 是標(biāo)準(zhǔn)庫中的一個符合上述條件的保留標(biāo)識符。所以,如果包含了相應(yīng)的標(biāo)準(zhǔn)頭文件而引入了 NULL 的話,則再在程序中重新定義 NULL 為不同的內(nèi)容是非法的,其行為是未定義的。也就是說,如果是符合標(biāo)準(zhǔn)的程序,其 NULL 的值只能是 0,不可能是除 0 之外的其它值,比如 1、2、3 等。
(7)malloc 函數(shù)在分配內(nèi)存失敗時返回 0 還是 NULL?
malloc 函數(shù)是標(biāo)準(zhǔn) C 規(guī)定的庫函數(shù)。在標(biāo)準(zhǔn)中明確規(guī)定了在其內(nèi)存分配失敗時返回的是空指針
39:如果NULL定義成#define NULL ((char *)0) 難道不就可以向函數(shù)傳入不加轉(zhuǎn)換的NULL了嗎?
不行。因?yàn)橛械臋C(jī)器不同類型數(shù)據(jù)的指針有不同的內(nèi)部表達(dá)。如果是字符指針的函數(shù)沒有問題, 但對于其它類型的指針參數(shù)仍然有問題, 而合法的構(gòu)造如FILE *fp = NULL;則會失敗。
如果定義#define NULL ((void *)0)除了潛在地幫助錯誤程序運(yùn)行以外, 這樣的定義還可以發(fā)現(xiàn)錯誤使用NULL 的程序。無論如何, ANSI 函數(shù)原型確保大多數(shù)指針參數(shù)在傳入函數(shù)時正確轉(zhuǎn)換。
40:使用非全零的值作為空指針內(nèi)部表達(dá)的機(jī)器上, NULL是如何定義的?
跟其它機(jī)器一樣: 定義為0 。當(dāng)程序員請求一個空指針時, 無論寫“0” 還是“NULL”, 都是有編譯器來生成適合機(jī)器的空指針的二進(jìn)制表達(dá)形式。因此, 在空指針的內(nèi)部表達(dá)不為0 的機(jī)器上定義NULL 為0 跟在其它機(jī)器上一樣合法:編譯器在指針上下文看到的未加修飾的0 都會被生成正確的空指針。
41:NULL 是什么, 它是怎么定義的?
很多人不愿意在程序中到處出現(xiàn)未加修飾的0。因此定義了預(yù)處理宏NULL為空指針常數(shù), 通常是0 或者((void *)0) 。希望區(qū)別整數(shù)0 和空指針0 的人可以在需要空指針的地方使用NULL。
42:用“if(p)” 判斷空指針是否可靠?如果空指針的內(nèi)部表達(dá)不是0 會怎么樣?
表達(dá)式中要求布爾值時:如果表達(dá)式等于0 則認(rèn)為該值為假。if(p) 等價于if(p != 0)。
43:怎樣在程序里獲得一個空指針?
在指針上下文中的常數(shù)0 會在編譯時轉(zhuǎn)換為空指針。
char *p = 0;
if(p != 0)
44:空指針到底是什么?
空指針表示“未分配” 或者“尚未指向任何地方” 的指針。
空指針可以確保不指向任何對象或函數(shù); 而未初始化指針則可能指向任何地方。
45:我能否用void** 指針作為參數(shù), 使函數(shù)按引用接受一般指針?
C 中沒有一般的指針的指針類型。void* 可以用作一般指針只是因?yàn)楫?dāng)它和其它類型相互賦值的時候, 如果需要, 它可以自動轉(zhuǎn)換成其它類型; 如果試圖這樣轉(zhuǎn)換所指類型為void* 之外的類型的void** 指針時, 這個轉(zhuǎn)換不能完成。
46:我有一個char * 型指針剛好指向一些int 型變量, 我想跳過它們。 為什么((int *)p)++; 不行?
類型轉(zhuǎn)換的實(shí)質(zhì)“把這些二進(jìn)制位看作另一種類型, 并作相應(yīng)的對待”; ((int *)p)++是一個轉(zhuǎn)換操作符, 根據(jù)定義它只能生成一個右值(rvalue)。而右值既不能賦值, 也不能用++ 自增。正確的做法:p = (char *)((int *)p + 1);
47:*p++ 自增p 還是p 所指向的變量?
*p++ 和*(p++) 等價。要自增p 指向的值, 使用(*p)++, 或者++*p。
48:我想聲明一個指針并為它分配一些空間,代碼char *p; *p = malloc(10)的問題;
你所聲明的指針是p, 而不是*p, 當(dāng)你操作指針本身時, 你只需要使用指針的名字即可:p = malloc(10);
49:int i=7; printf(“%d”, i++ *i++);的值?
i++*i++=49
50:枚舉和#define 有什么不同?1):#define 是在預(yù)編譯階段進(jìn)行簡單替換。枚舉常量則是在編譯的時候確定其值。
2):一般在編譯器里,可以調(diào)試枚舉常量,但是不能調(diào)試宏常量。
3):枚舉可以一次定義大量相關(guān)的常量,而#define 宏一次只能定義一個。
51:C++文件編譯與執(zhí)行的四個階段
第一階段:預(yù)處理階段。根據(jù)文件中的預(yù)處理指令來修改源文件的內(nèi)容。如#include指令,作用是把頭文件的內(nèi)容添加到.cpp文件中。
第二階段:編譯階段,將其翻譯成等價的中間代碼或匯編代碼。
第三階段:匯編階段,把匯編語言翻譯成目標(biāo)機(jī)器指令。
第四階段:是鏈接,例如,某個源文件中的函數(shù)可能引用了另一個源文件中定義的某個函數(shù);在程序中可能調(diào)用了某個庫文件中的函數(shù)。
52:聲明struct x1 { . . . }; 和typedef struct { . . . } x2; 有什么不同?
第一種形式聲明了一個“結(jié)構(gòu)標(biāo)簽”;
第二種聲明了一個“類型定義”。
主要的區(qū)別是第一種方式定義結(jié)構(gòu)體變量需要寫“struct x1”而引用第一種, 而第二種方式定義結(jié)構(gòu)體變量不需要使用struct 關(guān)鍵字。
53:以下的初始化有什么區(qū)別?
char a[] = “string literal”; char *p= “string literal”
用作數(shù)組初始值, 它指明該數(shù)組中字符的初始值。
第二種情況會轉(zhuǎn)化為一個無名的靜態(tài)字符數(shù)組, 可能會存儲在只讀內(nèi)存中, 這就是造成它不一定能被修改。第二個聲明把p 初始化成指向無名數(shù)組的第一個元素。為了編譯舊代碼, 有的編譯器有一個控制字符串是否可寫的開關(guān)。
54:對于沒有初始化的變量的初始值可以作怎樣的假定?如果一個全局變量初始值為“零”, 它可否作為空指針或浮點(diǎn)零?
對于具有“靜態(tài)” 生存期的未初始化全局變量可以確保初始值為零,如果是指針會被初始化為正確的空指針, 如果是浮點(diǎn)數(shù)會被初始化為0.0 。
對于局部變量,如果沒有顯示地初始化, 則包含的是垃圾內(nèi)容。
用malloc() 和realloc() 動態(tài)分配的內(nèi)存也可能包含垃圾數(shù)據(jù), 因此必須由調(diào)用者正確地初始化。
55:函數(shù)指針的定義是什么?
是一個指向函數(shù)的指針。看例子:
A),char * (*fun1)(char * p1,char * p2);//fun1 不是函數(shù)名,而是一個指針變量,它指向一個函數(shù)。這個函數(shù)有兩個指針類型的參數(shù),函數(shù)的返回值也是一個指針。
B),char * *fun2(char * p1,char * p2);//是個二級指針
C),char * fun3(char * p1,char * p2);//函數(shù)的返回值為char *類型
56:int *p = NULL 和*p = NULL 有什么區(qū)別?
int *p = NULL;//定義一個指針變量p,其指向的內(nèi)存里面保存的是int 類型的數(shù)據(jù);在定義變量p 的同時把p 的值設(shè)置為0×00000000,而不是把*p 的值設(shè)置為0×00000000
int *p;
*p = NULL;
給*p 賦值為NULL,即給p指向的內(nèi)存賦值為NULL;但是由于p 指向的內(nèi)存可能是非法的,所以調(diào)試的時候編譯器可
能會報(bào)告一個內(nèi)存訪問錯誤。
int i = 10;
int *p = &i;
*p = NULL;
在編譯器上調(diào)試一下,我們發(fā)現(xiàn)p 指向的內(nèi)存由原來的10 變?yōu)? 了;而p 本身的值, 即內(nèi)存地址并沒有改變。
57:介紹一下#error 預(yù)處理
#error 預(yù)處理指令的作用是,編譯程序時,只要遇到#error 就會生成一個編譯錯誤提示消息,并停止編譯。其語法格式為:
#error error-message
注意,宏串error-message 不用雙引號包圍。遇到#error 指令時,錯誤信息被顯示,可能同時還顯示編譯程序作者預(yù)先定義的其他內(nèi)容。
58:用變量a給出下面的定義
59:分別給出BOOL,int,float,指針變量 與“零值”比較的 if 語句(假設(shè)變量名為var)
BOOL型變量:if(!var)
int型變量: if(var==0)
float型變量:
const float EPSINON = 0.00001;
if ((x >= – EPSINON) && (x <= EPSINON)
指針變量: if(var==NULL)
60:什么是預(yù)編譯?何時需要預(yù)編譯?預(yù)編譯又稱為預(yù)處理 , 是做些代碼文本的替換工作。處理 # 開頭的指令 , 比如拷貝 #include 包含的文件代碼, #define 宏定義的替換 , 條件編譯等。
c 編譯系統(tǒng)在對程序進(jìn)行通常的編譯之前,先進(jìn)行預(yù)處理。 c 提供的預(yù)處理功能主要有以下三 種: 1 )宏定義 2 )文件包含 3 )條件編譯
61:內(nèi)聯(lián)函數(shù)與宏有什么區(qū)別
內(nèi)聯(lián)函數(shù)在編譯時展開,宏在預(yù)編譯時展開
在編譯的時候內(nèi)聯(lián)函數(shù)可以直接被嵌入到目標(biāo)代碼中,而宏只是一個簡單的文本替換
內(nèi)聯(lián)函數(shù)可以完成諸如類型檢測、語句是否正確等編譯功能,宏就不具備這樣的功能
inline函數(shù)是函數(shù),宏不是函數(shù)。
62:iostream與iostream.h的區(qū)別#include 非標(biāo)準(zhǔn)輸入輸出流
#include 標(biāo)準(zhǔn)輸入輸出流
有“.h”的就是非標(biāo)準(zhǔn)的,C的標(biāo)準(zhǔn)庫函數(shù),無“.h”的,就要用到命令空間,是C++的。63:namespace的使用因?yàn)闃?biāo)準(zhǔn)庫非常的龐大,所程序員在選擇的類的名稱或函數(shù)名時就很有可能和標(biāo)準(zhǔn)庫中的某個名字相同。所以為了避免這種情況所造成的名字沖突,就把標(biāo)準(zhǔn)庫中的一切都被放在名字空間std中。 C++標(biāo)準(zhǔn)程序庫中的所有標(biāo)識符都被定義于一個名為std的namespace中。
1、直接指定標(biāo)識符。例如std::ostream
2、使用using關(guān)鍵字。
using std::cout;
using std::endl;
3、最方便的就是使用using namespace std;
64:堆與棧的區(qū)別(1)一個是靜態(tài)的,一個是動態(tài)的,堆是靜態(tài)的,由用戶申請和釋放,棧是動態(tài)的,保存程序的局部變量(2)申請后系統(tǒng)的響應(yīng)不同
棧:只要棧的剩余空間大于申請空間,系統(tǒng)就為程序提供內(nèi)存,否則將拋出棧溢出異常
堆:當(dāng)系統(tǒng)收到程序申請時,先遍歷操作系統(tǒng)中記錄空閑內(nèi)存地址的鏈表,尋找第一個大于所申請空間的堆結(jié)點(diǎn),然后將該結(jié)點(diǎn)從空間結(jié)點(diǎn)鏈表中刪除,并將該結(jié)點(diǎn)的空間分配給程序。
(3)申請大小限制的不同
棧:在windows下,棧的大小一般是2M,如果申請的空間超過棧的剩余空間時,將提示overflow。
堆:堆是向高地址擴(kuò)展的數(shù)據(jù)結(jié)構(gòu),是不連續(xù)的內(nèi)存區(qū)域。這是由于系統(tǒng)是用鏈表來存儲的空閑內(nèi)存地址的,自然是不連續(xù)的,而鏈表的遍歷方向是由低地址向高地址。堆的大小受限于計(jì)算機(jī)系統(tǒng)中有效的虛擬內(nèi)存。由此可見,堆獲得的空間比較靈活,也比較大。 65:含參數(shù)的宏與函數(shù)的優(yōu)缺點(diǎn)
宏: 優(yōu)點(diǎn):在預(yù)處理階段完成,不占用編譯時間,同時,省去了函數(shù)調(diào)用的開銷,運(yùn)行效率高
缺點(diǎn):不進(jìn)行類型檢查,多次宏替換會導(dǎo)致代碼體積變大,而且由于宏本質(zhì)上是字符串替換,故可能會由于一些參數(shù)的副作用導(dǎo)致得出錯誤的結(jié)果。
函數(shù):優(yōu)點(diǎn):有類型檢查,比較安全。缺點(diǎn):函數(shù)調(diào)用需要參數(shù)、返回地址等的入棧、出棧開銷,效率沒有帶參數(shù)宏高
宏與內(nèi)聯(lián)函數(shù)的區(qū)別
內(nèi)聯(lián)函數(shù)和宏都是在程序出現(xiàn)的地方展開,內(nèi)聯(lián)函數(shù)不是通過函數(shù)調(diào)用實(shí)現(xiàn)的,是在調(diào)用該函數(shù)的程序處將它展開(在編譯期間完成的);宏同樣是;
不同的是:內(nèi)聯(lián)函數(shù)可以在編譯期間完成諸如類型檢測,語句是否正確等編譯功能;宏就不具有這樣的功能,而且宏展開的時間和內(nèi)聯(lián)函數(shù)也是不同的(在運(yùn)行期間展開)
66:多態(tài)的作用?
(1)可以隱藏實(shí)現(xiàn)的細(xì)節(jié),使得代碼模塊化;方便擴(kuò)展代碼;
(2)可以實(shí)現(xiàn)接口重用。
67: 類的靜態(tài)成員和非靜態(tài)成員有何區(qū)別?
靜態(tài)成員則是屬于這個類的非靜態(tài)成員是屬于每個對象的
68:C++純虛函數(shù),虛函數(shù),虛函數(shù)的實(shí)現(xiàn),什么是虛指針?
純虛函數(shù)是在基類中聲明的虛函數(shù),它在基類中沒有定義,但要求任何派生類都要定義自己的實(shí)現(xiàn)方法。
virtual void f()=0;//是一個接口,子類必須實(shí)現(xiàn)這個接口虛指針或虛函數(shù)指針是虛函數(shù)的實(shí)現(xiàn)細(xì)節(jié)。帶有虛函數(shù)的每一個對象都有一個虛指針指向該類的虛函數(shù)表。虛函數(shù) :虛函數(shù)是在基類中被聲明為virtual,并在派生類中重新定義的成員函數(shù),可實(shí)現(xiàn)成員函數(shù)的動態(tài)覆蓋(Override)
純虛函數(shù)和虛函數(shù)的區(qū)別是,純虛函數(shù)子類必須實(shí)現(xiàn)。 純虛函數(shù)的優(yōu)點(diǎn):(1)可以實(shí)現(xiàn)多態(tài)特性
(2)定義一個標(biāo)準(zhǔn)的接口,在派生類中必須予以重寫以實(shí)現(xiàn)多態(tài)性。
抽象類 :包含純虛函數(shù)的類稱為抽象類。由于抽象類包含了沒有定義的純虛函數(shù),所以不能定義抽象類的對象。
多態(tài)性可分為兩類:靜態(tài)多態(tài)和動態(tài)多態(tài)。函數(shù)重載和運(yùn)算符重載實(shí)現(xiàn)的多態(tài)屬于靜態(tài)多態(tài),動態(tài)多態(tài)性是通過虛函數(shù)實(shí)現(xiàn)的。
虛函數(shù)與構(gòu)造函數(shù),析構(gòu)函數(shù),成員函數(shù)的關(guān)系
為什么基類析構(gòu)函數(shù)是虛函數(shù)?
編譯器總是根據(jù)類型來調(diào)用類成員函數(shù)。但是一個派生類的指針可以安全地轉(zhuǎn)化為一個基類的指針。這樣刪除一個基類的指針的時候,C++不管這個指針指向一個基類對象還是一個派生類的對象,調(diào)用的都是基類的析構(gòu)函數(shù)而不是派生類的。如果你依賴于派生類的析構(gòu)函數(shù)的代碼來釋放資源,而沒有重載析構(gòu)函數(shù),那么會有資源泄漏。
為什么構(gòu)造函數(shù)不能為虛函數(shù)
虛函數(shù)采用一種虛調(diào)用的方法。需調(diào)用是一種可以在只有部分信息的情況下工作的機(jī)制。如果創(chuàng)建一個對象,則需要知道對象的準(zhǔn)確類型,因此構(gòu)造函數(shù)不能為虛函數(shù)。
如果虛函數(shù)是有效的,那為什么不把所有函數(shù)設(shè)為虛函數(shù)?
不行。因?yàn)槊總€虛函數(shù)的對象都要維護(hù)一個虛函數(shù)表,因此在使用虛函數(shù)的時候都會產(chǎn)生一定的系統(tǒng)開銷,這是沒有必要的。
69:面向?qū)ο蟮娜齻€基本特征,并簡單敘述之?
1. 封裝:將客觀事物抽象成類,每個類對自身的數(shù)據(jù)和方法。封裝可以使得代碼模塊化,目的是為了代碼重用
2. 繼承:子類繼承父類的方法和屬性,繼承可以擴(kuò)展已存在的代碼,目的是為了代碼重用
3. 多態(tài):允許將子類類型的指針賦值給父類類型的指針。
70:什么是“&(引用)”?申明和使用“引用”要注意哪些問題?
引用就是某個目標(biāo)變量的“別名”。注意事項(xiàng):(1)申明一個引用的時候,必須要對其進(jìn)行初始化。(2)初始化后,該引用名不能再作為其他變量名的別名。(3)引用本身不占存儲單元,系統(tǒng)不給引用分配存儲單元。(4)返回引用時,在內(nèi)存中不產(chǎn)生被返回值的副本
(5)不能返回局部變量的引用。主要原因是局部變量會在函數(shù)返回后被銷毀.
71:引用與多態(tài)的關(guān)系? 引用就是對象的別名。引用主要用作函數(shù)的形參。引用必須用與該引用同類型的對象初始化: 引用是除指針外另一個可以產(chǎn)生多態(tài)效果的手段。這意味著,一個基類的引用可以指向它的派生類實(shí)例。
int ival = 1024;int &refVal = ival; const 對象的引用只能是const類型的:const int ival = 1024;const int &refVal = ival; 多態(tài)是通過虛函數(shù)實(shí)現(xiàn)的。
72:指針和引用有什么區(qū)別;為什么傳引用比傳指針安全?如果我使用常量指針難道不行嗎?
(1) 引用在創(chuàng)建的同時必須初始化,保證引用的對象是有效的,所以不存在NULL引用;而指針在定義的時候不必初始化,所以,指針則可以是NULL,可以在定義后面的任何地方重新賦值。
(2) 引用一旦被初始化為指向一個對象,它就不能被改變?yōu)榱硪粋€對象的引用;而指針在任何時候都可以改變?yōu)橹赶蛄硪粋€對象.
(3) 引用的創(chuàng)建和銷毀并不會調(diào)用類的拷貝構(gòu)造函數(shù)
因?yàn)椴淮嬖诳找?#xff0c;并且引用一旦被初始化為指向一個對象,它就不能被改變?yōu)榱硪粋€對象的引用,所以比指針安全。
由于const 指針仍然存在空指針,并且有可能產(chǎn)生野指針,所以還是不安全
73:參數(shù)傳遞有幾種方式;實(shí)現(xiàn)多態(tài)參數(shù)傳遞采用什么方式,如果沒有使用某種方式原因是什么?
傳值,傳指針或者引用
74:拷貝構(gòu)造函數(shù)相關(guān)問題,深拷貝,淺拷貝,臨時對象等。
深拷貝意味著拷貝了資源和指針,而淺拷貝只是拷貝了指針,沒有拷貝資源
這樣使得兩個指針指向同一份資源,可能造成對同一份析構(gòu)兩次,程序崩潰。而且浪費(fèi)時間,并且不安全。
臨時對象的開銷比局部對象小些。
75:構(gòu)造函數(shù)的特點(diǎn)
構(gòu)造函數(shù)只在建立對象的時候自動被調(diào)用一次
構(gòu)造函數(shù)必須是公共的,否則無法生成對象
構(gòu)造函數(shù)只負(fù)責(zé)為自己的類構(gòu)造對象
在構(gòu)造函數(shù)中初始化變量
Person::Person( ) : name(“Jack”), age(30)
{
…
}
76:面向?qū)ο笕绾螌?shí)現(xiàn)數(shù)據(jù)隱藏
定義類來實(shí)現(xiàn)數(shù)據(jù)隱藏:
成員函數(shù)和屬性的類型:
私有成員private
保護(hù)成員protected
公共成員public
77:字符指針、浮點(diǎn)數(shù)指針、以及函數(shù)指針這三種類型的變量哪個占用的內(nèi)存最大?為什么?
所有指針變量占用內(nèi)存單元的數(shù)量都是相同的。
78:C++是不是類型安全的?
不是。兩個不同類型的指針之間可以強(qiáng)制轉(zhuǎn)換.
79:const char*, char const*, char *const的區(qū)別是什么?
把一個聲明從右向左讀,* 讀成指向
char * const cp;//cp是常指針,指向char類型的數(shù)據(jù)
const char * cp;//cp是char類型的指針,指向const char
char const * p;//C++里面沒有const*的運(yùn)算符,所以const屬于前面的類型。
80:什么是模板和宏?模板怎么實(shí)現(xiàn)?模板有什么缺點(diǎn)和優(yōu)點(diǎn)?模版特化的概念,為什么特化?
標(biāo)準(zhǔn)庫大量采用了模板技術(shù)。比如容器。
模板是一個藍(lán)圖,它本身不是類或函數(shù)。編譯器用模板產(chǎn)生指定的類或函數(shù)的特定類型版本。模版的形參分為類型形參和非類型形參類型形參就是表示類型的形參,跟在關(guān)鍵字typename后非類型形參用來表示常量表達(dá)式
81:空指針和懸垂指針的區(qū)別?
空指針是指被賦值為NULL的指針;delete指向動態(tài)分配對象的指針將會產(chǎn)生懸垂指針。
空指針可以被多次delete,而懸垂指針再次刪除時程序會變得非常不穩(wěn)定;
使用空指針和懸垂指針都是非法的,而且有可能造成程序崩潰,如果指針是空指針,盡管同樣是崩潰,但和懸垂指針相比是一種可預(yù)料的崩潰。
(a)指針數(shù)組和數(shù)組指針,函數(shù)指針和指針函數(shù)相關(guān)概念
指針數(shù)組:用于存儲指針的數(shù)組
int* a[4]
元素表示:*a[i]
數(shù)組指針:指向數(shù)組的指針
int (*a)[4]
元素表示:(*a)[i]
指針函數(shù):函數(shù)返回類型是某一類型的指針,int *f(x,y);
指針函數(shù)與函數(shù)指針表示方法的不同。最簡單的辨別方式就是看函數(shù)名前面的指針*號有沒有被括號()包含,如果被包含就是函數(shù)指針,反之則是指針函數(shù)。
函數(shù)指針:是指向函數(shù)的指針變量,即本質(zhì)是一個指針變量。
int (*f) (int x); /* 聲明一個函數(shù)指針 */ 類型說明符 (*指針的變量名)(參數(shù))
f=func; /* 將func函數(shù)的首地址賦給指針f */
指向函數(shù)的指針包含了函數(shù)的地址
指針的指針: 例如:char ** cp;
如果有三個星號,那就是指針的指針的指針,依次類推。 指針的指針需要用到指針的地址。
char c='A';
char *p=&c;
char **cp=&p;
通過指針的指針,不僅可以訪問它指向的指針,還可以訪問它指向的指針?biāo)赶虻臄?shù)據(jù):
char *p1=*cp;
char c1=**cp; 指向指針數(shù)組的指針: char *Names[]={ Bill,Sam,0};
char **nm=Names;
while(*nm!=0) printf(%s,*nm++);
先用字符型指針數(shù)組Names的地址來初始化指針nm。每次printf()的調(diào)用都首先傳遞指針nm指向的字符型指針,然后對nm進(jìn)行自增運(yùn)算使其指向數(shù)組的下一個元素(還是指針)。
82:什么是智能指針?
當(dāng)類中有指針成員時,一般有兩種方式來管理指針成員:
(1)每個類對象都保留一份指針指向的對象的拷貝;
(2)使用智能指針,從而實(shí)現(xiàn)指針指向的對象的共享。實(shí)質(zhì)是使用計(jì)數(shù)器與對象相關(guān)聯(lián),這樣做可以保證對象正確的刪除,避免垂懸指針。
每次創(chuàng)建類的新對象時,初始化指針并將引用計(jì)數(shù)置為1;當(dāng)對象作為另一對象的副本而創(chuàng)建時,拷貝構(gòu)造函數(shù)拷貝指針并增加與之相應(yīng)的引用計(jì)數(shù);對一個對象進(jìn)行賦值時,賦值操作符減少左操作數(shù)所指對象的引用計(jì)數(shù),并增加右操作數(shù)所指對象的引用計(jì)數(shù);調(diào)用析構(gòu)函數(shù)時,構(gòu)造函數(shù)減少引用計(jì)數(shù)。
83:C++空類默認(rèn)有哪些成員函數(shù)?
默認(rèn)構(gòu)造函數(shù)、析構(gòu)函數(shù)、復(fù)制構(gòu)造函數(shù)、賦值函數(shù)
84:哪一種成員變量可以在一個類的實(shí)例之間共享?
答:static靜態(tài)成員變量
85:什么是多態(tài)?多態(tài)有什么作用?如何實(shí)現(xiàn)的?多態(tài)的缺點(diǎn)?
多態(tài)就是一個接口,多種方法。所以說,多態(tài)的目的則是為了實(shí)現(xiàn)接口重用。也就是說,不論傳遞過來的究竟是那個類的對象,函數(shù)都能夠通過同一個接口調(diào)用到適應(yīng)各自對象的實(shí)現(xiàn)方法。
C++的多態(tài)性是通過虛函數(shù)來實(shí)現(xiàn)的,虛函數(shù)允許子類重新定義成員函數(shù),而子類重新定義父類的做法稱為覆蓋(override),或重寫。而重載則是允許有多個同名的函數(shù),而這些函數(shù)的參數(shù)列表不同,允許參數(shù)個數(shù)不同,參數(shù)類型不同。編譯器會根據(jù)函數(shù)列表的不同,而生成一些不同名稱的預(yù)處理函數(shù),來實(shí)現(xiàn)同名函數(shù)的重載。但這并沒有體現(xiàn)多態(tài)性。
多態(tài)與非多態(tài)的實(shí)質(zhì)區(qū)別就是函數(shù)的地址是運(yùn)行時確定還是編譯時確定。如果函數(shù)的調(diào)用在編譯器編譯期間就可以確定函數(shù)的調(diào)用地址,并生產(chǎn)代碼,是靜態(tài)的。而如果函數(shù)調(diào)用的地址在運(yùn)行時才確定,就是動態(tài)的。
最常見的用法就是聲明基類的指針,利用該指針指向任意一個子類對象,調(diào)用相應(yīng)的虛函數(shù),可以根據(jù)指向的子類的不同而實(shí)現(xiàn)不同的方法。如果沒有使用虛函數(shù)的話,即沒有利用C++多態(tài)性,則利用基類指針調(diào)用相應(yīng)的函數(shù)的時候,將總被限制在基類函數(shù)本身,而無法調(diào)用到子類中被重寫過的函數(shù)
86:虛函數(shù)表解析和內(nèi)存布局
虛函數(shù)表
虛函數(shù)是通過一張?zhí)摵瘮?shù)表來實(shí)現(xiàn)的。就像一個地圖一樣,指明了實(shí)際所應(yīng)該調(diào)用的函數(shù)的地址。
這里我們著重看一下這張?zhí)摵瘮?shù)表。C++的編譯器保證了虛函數(shù)表的指針存在于對象實(shí)例中最前面的位置(為了性能)。因此我們可以通過對象實(shí)例的地址得到這張?zhí)摵瘮?shù)表,然后通過遍歷其中函數(shù)指針,并調(diào)用相應(yīng)的函數(shù)。
為什么可以由父類的指針調(diào)用子類的對象的虛函數(shù):
Derive d;//Derive 是Base的子類
Base *b1 = &d;//這必須使用父類的指針???
b1->f(); //Derive::f()
87:公有繼承、受保護(hù)繼承、私有繼承
1)公有繼承時,派生類對象可以訪問基類中的公有成員,派生類的成員函數(shù)可以訪問基類中的公有和受保護(hù)成員;公有繼承時基類受保護(hù)的成員,可以通過派生類對象訪問但不能修改。
2)私有繼承時,基類的成員只能被直接派生類的成員訪問,無法再往下繼承;
3)受保護(hù)繼承時,基類的成員也只被直接派生類的成員訪問,無法再往下繼承。
88:有哪幾種情況只能用構(gòu)造函數(shù)初始化列表而不能用賦值初始化?
答:const成員,引用成員
89:C++如何阻止一個類被實(shí)例化?一般在什么時候?qū)?gòu)造函數(shù)聲明為private?
1)將類定義為抽象基類或者將構(gòu)造函數(shù)聲明為private;
2)不允許類外部創(chuàng)建類對象,只能在類內(nèi)部創(chuàng)建對象
90:類使用static成員的優(yōu)點(diǎn),如何訪問?
(1)static 成員的名字是在類的作用域中,因此可以避免與其他類的成員或全局對象名字沖突;
(2)可以實(shí)施封裝。static 成員可以是私有成員,而全局對象不可以;
(3) static 成員是與特定類關(guān)聯(lián)的,可清晰地顯示程序員的意圖。
91:static數(shù)據(jù)成員和static成員函數(shù)
(1)static數(shù)據(jù)成員:
static數(shù)據(jù)成員獨(dú)立于該類的任意對象而存在;static數(shù)據(jù)成員(const static數(shù)據(jù)成員除外)在類定義體內(nèi)聲明,必須在類外進(jìn)行初始化。不像普通數(shù)據(jù)成員,static成員不能在類的定義體中初始化,只能在定義時才初始化。 static數(shù)據(jù)成員定義放在cpp文件中,不能放在初始化列表中。Const static成員可就地初始化。
變量定義:用于為變量分配存儲空間,還可為變量指定初始值。程序中,變量有且僅有一個定義。
變量聲明:用于向程序表明變量的類型和名字。
(2)static成員函數(shù): 在類的外部定義,Static成員函數(shù)沒有this形參,它可以直接訪問所屬類的static成員,不能直接使用非static成員。因?yàn)閟tatic成員不是任何對象的組成部分,所以static成員函數(shù)不能被聲明為const。同時,static成員函數(shù)也不能被聲明為虛函數(shù)。
92:C++的內(nèi)部連接和外部連接
編譯單元:當(dāng)編譯cpp文件時,預(yù)處理器首先遞歸包含頭文件,形成一個編譯單元。這個編譯單元會被編譯成為一個與cpp文件名同名的目標(biāo)文件(.o或是.obj)。連接程序把不同編譯單元中產(chǎn)生的符號聯(lián)系起來,構(gòu)成一個可執(zhí)行程序。
內(nèi)部連接:如果一個名稱對于它的編譯單元來說是局部的,并且在連接時不會與其它編譯單元中的同樣的名稱相沖突,那么這個名稱有內(nèi)部連接:
a)所有的聲明
b)名字空間(包括全局名字空間)中的靜態(tài)自由函數(shù)、靜態(tài)友元函數(shù)、靜態(tài)變量的定義
c)enum定義
d)inline函數(shù)定義(包括自由函數(shù)和非自由函數(shù))
e)類的定義
f)名字空間中const常量定義
g)union的定義
外部連接:在一個多文件程序中,如果一個名稱在連接時可以和其它編譯單元交互,那么這個名稱就有外部連接。
以下情況有外部連接:
a)類非inline函數(shù)總有外部連接。包括類成員函數(shù)和類靜態(tài)成員函數(shù)
b)類靜態(tài)成員變量總有外部連接。
c)名字空間(包括全局名字空間)中非靜態(tài)自由函數(shù)、非靜態(tài)友元函數(shù)及非靜態(tài)變量
93:變量的分類,全局變量和局部變量有什么區(qū)別?實(shí)怎么實(shí)現(xiàn)的?操作系統(tǒng)和編譯器是怎么知道的?static全局變量與普通的全局變量有什么區(qū)別?static局部變量和普通局部變量有什么區(qū)別?static函數(shù)與普通函數(shù)有什么區(qū)別?
1)變量可以分為:全局變量、局部變量、靜態(tài)全局變量、靜態(tài)局部變量
靜態(tài)全局變量只在定義它的文件內(nèi)有效局部變量在定義它的函數(shù)內(nèi)有效,這個函數(shù)返回會后失效。
靜態(tài)局部變量只在定義它的函數(shù)內(nèi)有效,只是程序僅分配一次內(nèi)存,函數(shù)返回后,該變量不會消失,直到程序運(yùn)行結(jié)束后才釋放;全局變量和靜態(tài)變量如果沒有手工初始化,則由編譯器初始化為0。局部變量的值不可知。
變量的作用域:
形參變量只在被調(diào)用期間才分配內(nèi)存單元,調(diào)用結(jié)束立即釋放。 這一點(diǎn)表明形參變量只有在函數(shù)內(nèi)才是有效的, 離開該函數(shù)就不能再使用了。局部變量也稱為內(nèi)部變量。其作用域僅限于函數(shù)內(nèi), 離開該函數(shù)后再使用這種變量是非法的。
全局變量也稱為外部變量,它不屬于哪一個函數(shù),它屬于一個源程序文件。其作用域是整個源程序。在函數(shù)中使用全局變量,一般應(yīng)作全局變量說明。 只有在函數(shù)內(nèi)經(jīng)過說明的全局變量才能使用。全局變量的說明符為extern。 但在一個函數(shù)之前定義的全局變量,在該函數(shù)內(nèi)使用可不再加以說明。 對于全局變量還有以下幾點(diǎn)說明:
外部變量可加強(qiáng)函數(shù)模塊之間的數(shù)據(jù)聯(lián)系, 但是又使函數(shù)要依賴這些變量,因而使得函數(shù)的獨(dú)立性降低。從模塊化程序設(shè)計(jì)的觀點(diǎn)來看這是不利的, 因此在不必要時盡量不要使用全局變量。
在同一源文件中,允許全局變量和局部變量同名。在局部變量的作用域內(nèi),全局變量不起作用。
變量的存儲方式可分為“靜態(tài)存儲”和“動態(tài)存儲”兩種。
靜態(tài)存儲變量通常是在變量定義時就分定存儲單元并一直保持不變, 直至整個程序結(jié)束。動態(tài)存儲變量是在程序執(zhí)行過程中,使用它時才分配存儲單元, 使用完畢立即釋放。 如果一個函數(shù)被多次調(diào)用,則反復(fù)地分配、 釋放形參變量的存儲單元。從以上分析可知, 靜態(tài)存儲變量是一直存在的, 而動態(tài)存儲變量則時而存在時而消失。我們又把這種由于變量存儲方式不同而產(chǎn)生的特性稱變量的生存期。 生存期表示了變量存在的時間。 生存期和作用域是從時間和空間這兩個不同的角度來描述變量的特性,這兩者既有聯(lián)系,又有區(qū)別。 一個變量究竟屬于哪一種存儲方式, 并不能僅從其作用域來判斷,還應(yīng)有明確的存儲類型說明。
從作用域看:
全局變量具有全局作用域。全局變量只需在一個源文件中定義,就可以作用于所有的源文件。當(dāng)然,其他不包含全局變量定義的源文件需要用extern 關(guān)鍵字再次聲明這個全局變量。
靜態(tài)局部變量具有局部作用域,它只被初始化一次,自從第一次被初始化直到程序運(yùn)行結(jié)束都一直存在,它和全局變量的區(qū)別在于全局變量對所有的函數(shù)都是可見的,而靜態(tài)局部變量只對定義自己的函數(shù)體始終可見。
局部變量也只有局部作用域,它是自動對象(auto),它在程序運(yùn)行期間不是一直存在,而是只在函數(shù)執(zhí)行期間存在,函數(shù)的一次調(diào)用執(zhí)行結(jié)束后,變量被撤銷,其所占用的內(nèi)存也被收回。
靜態(tài)全局變量也具有全局作用域,它與全局變量的區(qū)別在于如果程序包含多個文件的話,它作用于定義它的文件里,不能作用到其它文件里,即被static關(guān)鍵字修飾過的變量具有文件作用域。這樣即使兩個不同的源文件都定義了相同名字的靜態(tài)全局變量,它們也是不同的變量。
從分配內(nèi)存空間看:
全局變量,靜態(tài)局部變量,靜態(tài)全局變量都在靜態(tài)存儲區(qū)分配空間,而局部變量在棧里分配空間。
全局變量本身就是靜態(tài)存儲方式,靜態(tài)全局變量當(dāng)然也是靜態(tài)存儲方式。這兩者在存儲方式上并無不同。這兩者的區(qū)別雖在于非靜態(tài)全局變量的作用域是整個源程序,當(dāng)一個源程序由多個源文件組成時,非靜態(tài)的全局變量在各個源文件中都是有效的。而靜態(tài)全局變量則限制了其作用域,即只在定義該變量的源文件內(nèi)有效,在同一源程序的其它源文件中不能使用它。由于靜態(tài)全局變量的作用域局限于一個源文件內(nèi),只能為該源文件內(nèi)的函數(shù)公用,因此可以避免在其它源文件中引起錯誤。
1)、靜態(tài)變量會被放在程序的靜態(tài)數(shù)據(jù)存儲區(qū)(全局可見)中,這樣可以在下一次調(diào)用的時候還可以保持原來的賦值。這一點(diǎn)是它與堆棧變量和堆變量的區(qū)別。
2)、變量用static告知編譯器,自己僅僅在變量的作用范圍內(nèi)可見。這一點(diǎn)是它與全局變量的區(qū)別。
程序的局部變量存在于(堆棧)中,全局變量存在于(靜態(tài)區(qū) )中,動態(tài)申請數(shù)據(jù)存在于( 堆)中。
94:應(yīng)用程序在運(yùn)行時的內(nèi)存包括代碼區(qū)和數(shù)據(jù)區(qū),其中數(shù)據(jù)區(qū)又包括哪些部分?
對于一個進(jìn)程的內(nèi)存空間而言,可以在邏輯上分成 3個部份:代碼區(qū),靜態(tài)數(shù)據(jù)區(qū)和動態(tài)數(shù)據(jù)區(qū)。
動態(tài)數(shù)據(jù)區(qū)一般就是“堆棧”。 棧是一種線性結(jié)構(gòu),堆是一種鏈?zhǔn)浇Y(jié)構(gòu)。進(jìn)程的每個線程都有私有的“棧”。
全局變量和靜態(tài)變量分配在靜態(tài)數(shù)據(jù)區(qū),本地變量分配在動態(tài)數(shù)據(jù)區(qū),即堆棧中。程序通過堆棧的基地址和偏移量來訪問本地變量。
95:C++里面是不是所有的動作都是main()引起的?如果不是,請舉例。
比如全局變量的初始化,就不是由main函數(shù)引起的:
class A{};
A a; //a的構(gòu)造函數(shù)限執(zhí)行
int main() {}
96:異??蚣?/p>
異常存在于程序的正常功能之外,并要求程序立即處理。 C++ 的異常處理包括:
1. throw 表達(dá)式,錯誤檢測部分使用這種表達(dá)式來說明遇到了不可處理的錯誤。
2. try 塊,錯誤處理部分使用它來處理異常。try 語句塊以 try 關(guān)鍵字開 始,并以一個或多個 catch 子句結(jié)束。在 try 塊中執(zhí)行的代碼所拋出 (throw)的異常,通常會被其中一個 catch 子句處理。
3. 由標(biāo)準(zhǔn)庫定義的一組異常類,用來在 throw 和相應(yīng)的 catch 之間傳遞有關(guān)的錯誤信息。 throw 表達(dá)式: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} 函數(shù)在尋找處理代碼的過程中退出在復(fù)雜的系統(tǒng)中,程序的執(zhí)行路徑也許在遇到拋出異常的代碼之前,就已經(jīng)經(jīng)過了多個 try 塊。拋出一個異常時,首先要搜索 的是拋出異常的函數(shù)。如果沒有找到匹配的 catch,則終止這個函數(shù)的執(zhí)行,并在調(diào)用這個函數(shù)的函數(shù)中尋找相配的 catch。如果仍然沒有找到相應(yīng)的處理代碼,該函數(shù)同樣要終止,搜索調(diào)用它的函數(shù)。直到找到適當(dāng)類型的 catch 為止。
總結(jié)
以上是生活随笔為你收集整理的while循环中指针会自动释放吗_C++】C++常见面试题汇总_持续更新中...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 转 Intellij中的常用快捷键
- 下一篇: c++ 操作oracle 最佳方式_or