1. 程式人生 > >C/C++面試題大彙總

C/C++面試題大彙總

原文地址:

前處理器(Preprocessor)

1 . 用預處理指令#define 宣告一個常數,用以表明1年中有多少秒(忽略閏年問題)
     #define SECONDS_PER_YEAR (60 * 60 * 24 * 365)UL
我在這想看到幾件事情:
1) #define 語法的基本知識(例如:不能以分號結束,括號的使用,等等)
2)懂得前處理器將為你計算常數表示式的值,因此,直接寫出你是如何計算一年中有多少秒而不是計算出實際的值,是更清晰而沒有代價的。
3) 意識到這個表示式將使一個16位機的整型數溢位-因此要用到長整型符號L,告訴編譯器這個常數是的長整型數
4) 如果你在你的表示式中用到UL(表示無符號長整型),那麼你有了一個好的起點

。記住,第一印象很重要。

2 . 寫一個"標準"巨集MIN ,這個巨集輸入兩個引數並返回較小的一個。
#define MIN(A,B) ((A) <= (B) ? (A) : (B)) 
這個測試是為下面的目的而設的:
1) 標識#define在巨集中應用的基本知識。這是很重要的。因為在 嵌入(inline)操作符 變為標準C的一部分之前,巨集是方便產生嵌入程式碼的唯一方法,對於嵌入式系統來說,為了能達到要求的效能,嵌入程式碼經常是必須的方法。
2)三重條件操作符的知識。這個操作符存在C語言中的原因是它使得編譯器能產生比if-then-else更優化的程式碼,瞭解這個用法是很重要的。
3) 懂得在巨集中小心地把引數用括號括起來
4) 我也用這個問題開始討論巨集的副作用,例如:當你寫下面的程式碼時會發生什麼事?
least = MIN(*p++, b);

死迴圈(Infinite loops)

4. 嵌入式系統中經常要用到無限迴圈,你怎麼樣用C編寫死迴圈呢?
這個問題用幾個解決方案。我首選的方案是:

while(1)
{

}

一些程式設計師更喜歡如下方案:

for(;;)
{

}

這個實現方式讓我為難,因為這個語法沒有確切表達到底怎麼回事。如果一個應試者給出這個作為方案,我將用這個作為一個機會去探究他們這樣做的基本原理。如果他們的基本答案是:"我被教著這樣做,但從沒有想到過為什麼。"這會給我留下一個壞印象。

第三個方案是用 goto
Loop:
...
goto Loop;
應試者如給出上面的方案,這說明或者他是一個組合語言程式設計師(這也許是好事)或者他是一個想進入新領域的BASIC/FORTRAN程式設計師。

資料宣告(Data declarations)

5. 用變數a給出下面的定義
a) 一個整型數(An integer) 
b)一個指向整型數的指標( A pointer to an integer) 
c)一個指向指標的的指標,它指向的指標是指向一個整型數( A pointer to a pointer to an intege)r 
d)一個有10個整型數的陣列( An array of 10 integers) 
e) 一個有10個指標的陣列,該指標是指向一個整型數的。(An array of 10 pointers to integers) 
f) 一個指向有10個整型數陣列的指標( A pointer to an array of 10 integers) 
g) 一個指向函式的指標,該函式有一個整型引數並返回一個整型數(A pointer to a function that takes an integer as an argument and returns an integer) 
h) 一個有10個指標的陣列,該指標指向一個函式,該函式有一個整型引數並返回一個整型數( An array of ten pointers to functions that take an integer argument and return an integer )

答案是: 
a) int a; // An integer 
b) int *a; // A pointer to an integer 
c) int **a; // A pointer to a pointer to an integer 
d) int a[10]; // An array of 10 integers 
e) int *a[10]; // An array of 10 pointers to integers 
f) int (*a)[10]; // A pointer to an array of 10 integers 
g) int (*a)(int); // A pointer to a function a that takes an integer argument and returns an integer 
h) int (*a[10])(int); // An array of 10 pointers to functions that take an integer argument and return an integer

人們經常聲稱這裡有幾個問題是那種要翻一下書才能回答的問題,我同意這種說法。當我寫這篇文章時,為了確定語法的正確性,我的確查了一下書。但是當我被面試的時候,我期望被問到這個問題(或者相近的問題)。因為在被面試的這段時間裡,我確定我知道這個問題的答案。應試者如果不知道所有的答案(或至少大部分答案),那麼也就沒有為這次面試做準備,如果該面試者沒有為這次面試做準備,那麼他又能為什麼出準備呢?

Static

6. 關鍵字static的作用是什麼?
這個簡單的問題很少有人能回答完全。在C語言中,關鍵字static有三個明顯的作用:
1) 無論在函式體內,類內,還是全域性變數,全域性靜態變數,在程式啟動的時候,靜態變數,全域性變數的空間已經分配好了
2) 在模組內(但在函式體外),一個被宣告為靜態的變數可以被模組內所用函式訪問,但不能被模組外其它函式訪問。它是一個本地的全域性變數。
3) 在模組內,一個被宣告為靜態的函式只可被這一模組內的其它函式呼叫。那就是,這個函式被限制在宣告它的模組的本地範圍內使用。

大多數應試者能正確回答第一部分,一部分能正確回答第二部分,同是很少的人能懂得第三部分。這是一個應試者的嚴重的缺點,因為他顯然不懂得本地化資料和程式碼範圍的好處和重要性。

Const

7.關鍵字const有什麼含意?
       我只要一聽到被面試者說:"const意味著常數",我就知道我正在和一個業餘者打交道。去年Dan Saks已經在他的文章裡完全概括了const的所有用法,因此ESP(譯者:Embedded Systems Programming)的每一位讀者應該非常熟悉const能做什麼和不能做什麼.如果你從沒有讀到那篇文章,只要能說出const意味著"只讀"就可以了。儘管這個答案不是完全的答案,但我接受它作為一個正確的答案。(如果你想知道更詳細的答案,仔細讀一下Saks的文章吧。)
如果應試者能正確回答這個問題,我將問他一個附加的問題:
下面的宣告都是什麼意思?

const int a;
int const a;
const int *a;
int * const a;
int const * a const;

/******/
前兩個的作用是一樣,a是一個常整型數。第三個意味著a是一個指向常整型數的指標(也就是,整型數是不可修改的,但指標可以)。第四個意思a是一個指向整型數的常指標(也就是說,指標指向的整型數是可以修改的,但指標是不可修改的)。最後一個意味著a是一個指向常整型數的常指標(也就是說,指標指向的整型數是不可修改的,同時指標也是不可修改的)。如果應試者能正確回答這些問題,那麼他就給我留下了一個好印象。順帶提一句,也許你可能會問,即使不用關鍵字 const,也還是能很容易寫出功能正確的程式,那麼我為什麼還要如此看重關鍵字const呢?我也如下的幾下理由:
1) 關鍵字const的作用是為給讀你程式碼的人傳達非常有用的資訊,實際上,宣告一個引數為常量是為了告訴了使用者這個引數的應用目的。如果你曾花很多時間清理其它人留下的垃圾,你就會很快學會感謝這點多餘的資訊。(當然,懂得用const的程式設計師很少會留下的垃圾讓別人來清理的。)
2) 通過給優化器一些附加的資訊,使用關鍵字const也許能產生更緊湊的程式碼。
3) 合理地使用關鍵字const可以使編譯器很自然地保護那些不希望被改變的引數,防止其被無意的程式碼修改。簡而言之,這樣可以減少bug的出現。

7.C++中為什麼用模板類。
答:(1)可用來建立動態增長和減小的資料結構
(2)它是型別無關的,因此具有很高的可複用性。
(3)它在編譯時而不是執行時檢查資料型別,保證了型別安全
(4)它是平臺無關的,可移植性
(5)可用於基本資料型別

13.C++中什麼資料分配在棧或堆中,New分配資料是在近堆還是遠堆中?
答:棧: 存放區域性變數,函式呼叫引數,函式返回值,函式返回地址。由系統管理
堆: 程式執行時動態申請,new 和 malloc申請的記憶體就在堆上

15函式模板與類模板有什麼區別?
答:函式模板的例項化是由編譯程式在處理函式呼叫時自動完成的,

而類模板的例項化必須由程式設計師在程式中顯式地指定。

16一般資料庫若出現日誌滿了,會出現什麼情況,是否還能使用?
答:只能執行查詢等讀操作,不能執行更改,備份等寫操作,原因是任何寫操作都要記錄日誌。也就是說基本上處於不能使用的狀態。

22.TCP/IP 建立連線的過程?(3-way shake)
答:在TCP/IP協議中,TCP協議提供可靠的連線服務,採用三次握手建立一個連線。
  第一次握手:建立連線時,客戶端傳送syn包(syn=j)到伺服器,並進入SYN_SEND狀態,等待伺服器確認;
       第二次握手:伺服器收到syn包,必須確認客戶的SYN(ack=j+1),同時自己也傳送一個SYN包(syn=k),即SYN+ACK包,此時伺服器進入SYN_RECV狀態;
  第三次握手:客戶端收到伺服器的SYN+ACK包,向伺服器傳送確認包ACK(ack=k+1),此包傳送完畢,客戶端和伺服器進入ESTABLISHED狀態,完成三次握手。

23.ICMP是什麼協議,處於哪一層?
答:Internet控制報文協議,處於網路層(IP層)

2.引用與指標有什麼區別?
1) 引用必須被初始化,指標不必。
2) 引用初始化以後不能被改變,指標可以改變所指的物件。
3) 不存在指向空值的引用,但是存在指向空值的指標。

7.什麼函式不能宣告為虛擬函式?
constructor函式不能宣告為虛擬函式。  

12.IP地址的編碼分為哪倆部分?
IP地址由兩部分組成,網路號和主機號。不過是要和“子網掩碼”按位與上之後才能區分哪些是網路位哪些是主機位。

1、static全域性變數與普通的全域性變數有什麼區別?static區域性變數和普通區域性變數有什麼區別?static函式與普通函式有什麼區別?
答:全域性變數(外部變數)的說明之前再冠以static 就構成了靜態的全域性變數。全域性變數本身就是靜態儲存方式, 靜態全域性變數當然也是靜態儲存方式。 這兩者在儲存方式上並無不同。這兩者的區別雖在於非靜態全域性變數的作用域是整個源程式, 當一個源程式由多個原始檔組成時,非靜態的全域性變數在各個原始檔中都是有效的。 而靜態全域性變數則限制了其作用域, 即只在定義該變數的原始檔內有效, 在同一源程式的其它原始檔中不能使用它。由於靜態全域性變數的作用域侷限於一個原始檔內,只能為該原始檔內的函式公用, 因此可以避免在其它原始檔中引起錯誤。
從以上分析可以看出, 把區域性變數改變為靜態變數後是改變了它的儲存方式即改變了它的生存期。把全域性變數改變為靜態變數後是改變了它的作用域, 限制了它的使用範圍。
static函式與普通函式作用域不同。僅在本檔案。只在當前原始檔中使用的函式應該說明為內部函式(static),內部函式應該在當前原始檔中說明和定義。對於可在當前原始檔以外使用的函式,應該在一個頭檔案中說明,要使用這些函式的原始檔要包含這個標頭檔案
static全域性變數與普通的全域性變數有什麼區別:static全域性變數只初使化一次,防止在其他檔案單元中被引用;
static區域性變數和普通區域性變數有什麼區別:static區域性變數只被初始化一次,下一次依據上一次結果值;
static函式與普通函式有什麼區別:static函式在記憶體中只有一份,普通函式在每個被呼叫中維持一份拷貝