C/C++常見面試題

1. C中static有什麼作用

(1)隱藏。 當我們同時編譯多個文件時,所有未加static前綴的全局變量和函數都具有全局可見性,故使用static在不同的文件中定義同名函數和同名變量,而不必擔心命名衝突。
(2)static的第二個作用是保持變量內容的持久。存儲在靜態數據區的變量會在程序剛開始運行時就完成初始化,也是唯一的一次初始化。共有兩種變量存儲在靜態存儲區:全局變量和static變量。
(3)static的第三個作用是默認初始化爲0。其實全局變量也具備這一屬性,因爲全局變量也存儲在靜態數據區。在靜態數據區,內存中所有的字節默認值都是0×00,某些時候這一特點可以減少程序員的工作量。


2.C++中const有什麼用?

不要一聽到const就說是常量,這樣給考官一種在和一個外行交談的感覺。應該說const修飾的內容不可改變就行了, 定義常量只是一種使用方式而已,還有const數據成員,const參數, const返回值, const成員函數等, 被const修飾的東西都受到強制保護,可以預防意外的變動,能提高程序的健壯性。

 

3. C與C++各自是如何定義常量的?有什麼不同?

C中是使用宏#define定義, C++使用更好的const來定義。
區別:

1)const是有數據類型的常量,而宏常量沒有,編譯器可以對前者進行靜態類型安全檢查,對後者僅是字符替換,沒有類型安全檢查,而且在字符替換時可能會產生意料不到的錯誤(邊際效應)。

2)有些編譯器可以對const常量進行調試, 不能對宏調試。


4. 既然C++中有更好的const爲什麼還要使用宏?

const無法代替宏作爲衛哨來防止文件的重複包含。


5. C++中引用和指針的區別?

引用是對象的別名, 操作引用就是操作這個對象, 必須在創建的同時有效得初始化(引用一個有效的對象, 不可爲NULL), 初始化完畢就再也不可改變, 引用具有指針的效率, 又具有變量使用的方便性和直觀性, 在語言層面上引用和對象的用法一樣, 在二進制層面上引用一般都是通過指針來實現的, 只是編譯器幫我們完成了轉換. 之所以使用引用是爲了用適當的工具做恰如其分的事, 體現了最小特權原則.


6. 說一說C與C++的內存分配方式?

1)從靜態存儲區域分配。內存在程序編譯的時候就已經分配好,這塊內存在程序的整個運行期間都存在,如全局變量,static變量。

2)在棧上創建。在執行函數時,函數內局部變量的存儲單元都可以在棧上創建,函數執行結束時這些存儲單元自動被釋放。棧內存分配運算內置於處理器的指令集中,效率很高,但是分配的內存容量有限。

3)從堆上分配(動態內存分配)程序在運行的時候用malloc或new申請任意多少的內存,程序員負責在何時用free或delete釋放內存。動態內存的生存期自己決定,使用非常靈活。


7. new/delete 與 malloc()/free() 的區別?

malloc() 與 free() 是C語言的標準庫函數, new/delete 是C++的運算符, 他們都可以用來申請和釋放內存, malloc()和free()不在編譯器控制權限之內, 不能把構造函數和析構函數的任務強加給他們.


8. #include<a.h>和#include“a.h” 有什麼區別?

答:對於#include <a.h> ,編譯器從標準庫路徑開始搜索 a.h對於#include “a.h” ,編譯器從用戶的工作路徑開始搜索 a.h


9. 在C++ 程序中調用被 C編譯器編譯後的函數,爲什麼要加 extern “C”?

C++語言支持函數重載,C語言不支持函數重載。函數被C++編譯後在庫中的名字與C語言的不同。假設某個函數的原型爲: void foo(int x, int y);該函數被C編譯器編譯後在庫中的名字爲_foo,而C++編譯器則會產生像_foo_int_int之類的名字。C++提供了C連接交換指定符號extern“C”來解決名字匹配問題。


10. C++中的什麼是多態性? 是如何實現的?

多態性是面向對象程序設計語言繼數據抽象和繼承之後的第三個基本特徵。它是在運行時出現的多態性通過派生類和虛函數實現。基類和派生類中使用同樣的函數名, 完成不同的操作具體實現相隔離的另一類接口,即把“ w h a t”從“h o w”分離開來。多態性提高了代碼的組織性和可讀性,虛函數則根據類型的不同來進行不同的隔離。

11. 什麼是動態特性?

在絕大多數情況下, 程序的功能是在編譯的時候就確定下來的, 我們稱之爲靜態特性. 反之, 如果程序的功能是在運行時刻才能確定下來的, 則稱之爲動態特性。C++中, 虛函數,抽象基類, 動態綁定和多態構成了出色的動態特性。


12.什麼是封裝?C++中是如何實現的?

封裝來源於信息隱藏的設計理念, 是通過特性和行爲的組合來創建新數據類型讓接口與具體實現相隔離。C++中是通過類來實現的, 爲了儘量避免某個模塊的行爲干擾同一系統中的其它模塊,應該讓模塊僅僅公開必須讓外界知道的接口.


13. 什麼是RTTI?

RTTI事指運行時類型識別(Run-time type identification)在只有一個指向基類的指針或引用時確定一個對象的準確類型。


14. 什麼是拷貝構造函數?

它是單個參數的構造函數,其參數是與它同屬一類的對象的(常)引用;類定義中,如果未提供自己的拷貝構造函數,C++提供一個默認拷貝構造函數,該默認拷貝構造函數完成一個成員到一個成員的拷貝


15. 什麼是深淺拷貝?

淺拷貝是創建了一個對象用一個現成的對象初始化它的時候只是複製了成員(簡單賦值)而沒有拷貝分配給成員的資源(如給其指針變量成員分配了動態內存); 深拷貝是當一個對象創建時,如果分配了資源,就需要定義自己的拷貝構造函數,使之不但拷貝成員也拷貝分配給它的資源.


16.面向對象程序設計的優點?

開發時間短, 效率高, 可靠性高。面向對象編程的編碼具有高可重用性,可以在應用程序中大量採用成熟的類庫(如STL),從而雖短了開發時間,軟件易於維護和升級。


1.指針和引用有什麼分別;如果傳引用比傳指針安全,爲什麼?如果我使用常量指針難道不行嗎?

     (1) 引用在創建的同時必須初始化,即引用到一個有效的對象;而指針在定義的時候不必初始化,可以在定義後面的任何地方重新賦值.

     (2) 不存在NULL引用,引用必須與合法的存儲單元關聯;而指針則可以是NULL.

     (3) 引用一旦被初始化爲指向一個對象,它就不能被改變爲另一個對象的引用;而指針在任何時候都可以改變爲指向另一個對象.
給引用賦值並不是改變它和原始對象的綁定關係.

     (4) 引用的創建和銷燬並不會調用類的拷貝構造函數

     (5) 語言層面,引用的用法和對象一樣;在二進制層面,引用一般都是通過指針來實現的,只不過編譯器幫我們完成了轉換.

     不存在空引用,並且引用一旦被初始化爲指向一個對象,它就不能被改變爲另一個對象的引用,顯得很安全。

     const 指針仍然存在空指針,並且有可能產生野指針.

     總的來說:引用既具有指針的效率,又具有變量使用的方便性和直觀性.


2.構造函數可否是虛汗數,爲什麼?析構函數呢,可否是純虛的呢?

     構造函數不能爲虛函數,要構造一個對象,必須清楚地知道要構造什麼,否則無法構造一個對象。

     析構函數可以爲純虛函數。

3.爲什麼要引入抽象基類和純虛函數?

     主要目的是爲了實現一種接口的效果。


4. 結構與聯合有和區別?

(1). 結構和聯合都是由多個不同的數據類型成員組成, 但在任何同一時刻, 聯合中只存放了一個被選中的成員(所有成員共用一塊地址空間), 
而結構的所有成員都存在(不同成員的存放地址不同)。

(2). 對於聯合的不同成員賦值, 將會對其它成員重寫, 原來成員的值就不存在了, 而對於結構的不同成員賦值是互不影響的。


5. #include<file.h> 與 #include "file.h"的區別?

答: 前者是從Standard Library的路徑尋找和引用file.h,而後者是從當前工作路徑搜尋並引用file.h, 如果後者沒有找到對應的文件,就按前者的路徑去尋找。


6. 面向對象的三個基本特徵,並簡單敘述之?

   (1). 封裝:將客觀事物抽象成類,每個類對自身的數據和方法實行protection(private, protected,public)

   (2). 繼承:廣義的繼承有三種實現形式:實現繼承(指使用基類的屬性和方法而無需額外編碼的能力)、可視繼承(子窗體使用父窗體的外觀和實現代碼)、接口繼承(僅使用屬性和方法,實現滯後到子類實現)。前兩種(類繼承)和後一種(對象組合=>接口繼承以及純虛函數)構成了功能複用的兩種方式。

   (3). 多態:是將父對象設置成爲和一個或更多的他的子對象相等的技術,賦值之後,父對象就可以根據當前賦值給它的子對象的特性以不同的方式運作。簡單的說,就是一句話:允許將子類類型的指針賦值給父類類型的指針。 

7. 重載(overload)和重寫(overried,有的書也叫做“覆蓋”)的區別?

   從定義上來說: 
重載:是指允許存在多個同名函數,而這些函數的參數表不同(或許參數個數不同,或許參數類型不同,或許兩者都不同)。 
   重寫:是指子類重新定義復類虛函數的方法。


8. 什麼是預編譯,何時需要預編譯:總是使用不經常改動的大型代碼體。

   程序由多個模塊組成,所有模塊都使用一組標準的包含文件和相同的編譯選項。在這種情況下,可以將所有包含文件預編譯爲一個預編譯頭。

9. 一個由c/C++編譯的程序佔用的內存分爲以下幾個部分 
(1)、棧區(stack)—      由編譯器自動分配釋放 ,存放函數的參數值,局部變量的值等。其操作方式類似於數據結構中的棧。在WINDOWS下,棧的大小是2M(也有的說是1M,總之是一個編譯時就確定的常數),如果申請的空間超過棧的剩餘空間時,將提示overflow。因此,能從棧獲得的空間較小 
(2)、堆區(heap) —      一般由程序員分配釋放, 若程序員不釋放,程序結束時可能由OS回收 。注意它與數據結構中的堆是兩回事,分配方式倒是類似於鏈表,堆是向高地址擴展的數據結構,是不連續的內存區域。這是由於系統是用鏈表來存儲的空閒內存地址的,自然是不連續的,而鏈表的遍歷方向是由低地址向高地址。堆的大小受限於計算機系統中有效的虛擬內存。由此可見,堆獲得的空間比較靈活,也比較大。。 
(3)、全局區(靜態數據區)(static)—,全局變量和靜態變量的存儲是放在一塊的,初始化的全局變量和靜態變量在一塊區域,未初始化的全局變量和未初始化的靜態變量在相鄰的另一塊區域。 - 程序結束後有系統釋放 
(4)、文字常量區 —      常量字符串就是放在這裏的。 程序結束後由系統釋放 
(5)、程序代碼區 —      存放函數體的二進制代碼。

10. new和malloc的區別?
(1)、new 是c++中的操作符,malloc是c 中的一個函數, new可以認爲是malloc加構造函數的執行。

(2)、new 不止是分配內存,而且會調用類的構造函數,同理delete會調用類的析構函數,而malloc則只分配內存,不會進行初始化類成員的工作,同樣free也不會調用析構函數

11. 解釋下函數指針?
“函數指針”本身首先應是指針變量,只不過該指針變量指向函數。每一個函數都有一個入口地址,該入口地址就是函數指針所指向的地址。
有了指向函數的指針變量後,可用該指針變量調用函數,就如同用指針變量可引用其他類型變量一樣,在這些概念上一致的。
int func(int x); /* 聲明一個函數 */
int (*f) (int x); /* 聲明一個函數指針 */
f=func;           /* 將func函數的首地址賦給指針f */

12. int (*s[10])(int) 表示的是什麼? 
int (*s[10])(int) 函數指針數組,每個指針指向一個int func(int param)的函數。

13. 進程和線程的區別?
進程是系統進行資源分配和調度的一個獨立單位. 進程在執行過程中擁有獨立的內存單元,線程是進程的一個實體,是CPU調度和分派的基本單位,
它是比進程更小的能獨立運行的基本單位.線程自己基本上不擁有系統資源,一個進程有多個線程,這些線程共享內存,從而極大地提高了程序的運行效率。

14. 多線程和多進程的區別?
線程執行開銷小,但不利於資源管理和保護;而進程正相反.       

       用多進程每個進程有自己的地址空間(address space),線程則共享地址空間。所有其它區別都是由此而來的:

       (1)速度:線程產生的速度快,線程間的通訊快、切換快等,因爲他們在同一個地址空間內。

       (2)資源利用率:線程的資源利用率比較好也是因爲他們在同一個地址空間內。

       (3)同步問題:線程使用公共變量/內存時需要使用同步機制還是因爲他們在同一個地址空間內。


15. 如何判斷一個單鏈表是有環的?(注意不能用標誌位,最多隻能用兩個額外指針) 
一種O(n)的辦法就是(搞兩個指針,一個a每次遞增一步,一個b每次遞增兩步,如果有環的話兩者必然重合,反之亦然),因爲每次b比a多走一步,和追趕問題一樣,總會
追趕上,最多走n步(n爲單鏈表的長度).

16. 用兩個棧實現一個隊列的功能?要求給出算法和思路!

      設2個棧爲A,B, 一開始均爲空.

      入隊: 將新元素push入棧A;

      出隊:

            (1)判斷棧B是否爲空;

            (2)如果爲空,則將棧A中所有元素依次pop出並push到棧B;

            (3)將棧B的棧頂元素pop出;這樣實現的隊列入隊和出隊的平攤複雜度都還是O(1)


17. 緩衝區溢出是指當計算機向緩衝區內填充數據位數時超過了緩衝區本身的容量,溢出的數據覆蓋在合法數據上,
void function(char *str) { 
char buffer[16]; 
strcpy(buffer,str); 

上面的strcpy()將直接吧str中的內容copy到buffer中。這樣只要str的長度大於16,就會造成buffer的溢出,使程序運行出錯。存在象strcpy這樣的問題的標準函數還有strcat(),sprintf(),vsprintf(),gets(),scanf()等。

18.全局變量和靜態變量的區別?   
   全局變量和靜態全局變量的區別在於作用域不同,一個項目裏如果有多個源程序文件,非靜態全局變量可以在所有源文件裏調用,靜態全局變量只能在本文件裏調用,不允許在其他文件裏調用。


發佈了8 篇原創文章 · 獲贊 7 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章