面試準備-C++

C++面試

1.c++與c區別

2.union共同體和struct結構體的區別

3. static的作用

4.const的作用

5.指針和引用的區別

6. 重載、重寫、隱藏的區別

7.虛函數與虛函數表相關知識點

8.C++中struct和class的區別

9數組指針和指針數組

10.strlen和sizeof的區別

11.進程和線程

12.C/C++內存有哪幾種類型?

13.堆和棧的區別?

14.什麼是內存泄漏?面對內存泄漏和指針越界,你有哪些方法?你通常採用哪些方法來避免和減少這類錯誤?

15. 函數調用的過程?

16. 左值和右值

18. 宏和內聯(inline)函數的比較?

19.C++中有了malloc / free , 爲什麼還需要 new / delete?

20.強制類型轉化

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

22.頭文件中的 ifndef/define/endif 是幹什麼用的? 該用法和 program once 的區別?

23.說幾個C++11的新特性

24. 32位,64位系統中,各種常用內置數據類型佔用的字節數?

25.virtual, inline, decltype,volatile,static, const關鍵字的作用?使用場景?

26.深拷貝與淺拷貝的區別?

27.計算類大小例子

28.大端與小端的概念?各自的優勢是什麼?

29.C/C++中堆和棧的區別

30.指針常量與常量指針

31、函數模板與類模板有什麼區別?

32.智能指針

1.c++與c區別

答:C 是面向過程的一門編程語言,C++ 可以很好地進行面向對象的程序設計,

C++ 對 C 的增強,表現在六個方面:

  • 增強了類型檢查機制
  • 增加了面向對象的機制
  • 增加了泛型編程的機制(template)
  • 增加了異常處理
  • 增加了重載的機制
  • 增加了標準模板庫

 參考:https://www.jianshu.com/p/2522b07219ae

2.union共同體和struct結構體的區別

  • struct和union都是由多個不同的數據類型成員組成
  • 同一時刻,union只存放了一個數據成員,而struct的所有成員都存在
  • 在struct中,每個成員都有自己的內存,它們同時存在,在union中,所有成員不能同時佔用各自的一塊內存,因此不能同時存在,只能存在一個
  • struct的長度爲所有成員長度之和,union的長度爲最長成員的長度
  • 對union不同成員賦值會重寫其他成員,而struct的不同成員之間的賦值互不影響

3. static的作用

  • 修飾局部變量,改變了局部變量的存儲區(棧->靜態存儲區)以及生命週期(離開作用於之後,並未被銷燬,仍然駐留在內存,直到程序銷燬,但是我們不能再對它進行訪問),但未改變其作用域。
  • 修飾全局變量和函數,並未改變其存儲位置及生命週期,而改變了其作用域,使當前文件外的源文件無法訪問該變量和該函數。
  • 修飾類的成員變量,使其成爲類的全局變量,被類的所有對象共享。
  • 修飾類的成員函數,所有對象共享該函數,函數屬於類的,不需要創建對象即可訪問;靜態成員函數只能訪問靜態成員變量,不可訪問非靜態成員變量。

4.const的作用

  • 限定變量爲不可修改
  • 限定成員函數不可以修改任何數據成員

5.指針和引用的區別

  • 指針是變量,存放變量的地址,佔用4Byte或者8Byte,引用是別名,不佔用內存空間
  • 指針可以爲空,可以聲明之後再初始化,引用必須在聲明的時候初始化,而且初始化之後不可再改變
  • 指針可以有多級,引用不可以

6. 重載、重寫、隱藏的區別

Overload(重載):在C++程序中,可以將語義、功能相似的幾個函數用同一個名字表示,但是參數或者返回值不同

  • 相同的範圍(同一個類中)
  • 函數名相同
  • 參數或者返回值不同
  • virtual關鍵字可有可無

Override(重寫):派生類函數覆蓋基類函數,用於多態

  • 不同的範圍(分別位於基類和派生類)
  • 函數名相同
  • 參數和返回值相同
  • 必須有virtual關鍵字

Overwrite(隱藏),派生類函數屏蔽與其同名的基類函數規則如下

  • 派生類與基類函數同名,但是參數不同,基類函數將被隱藏
  • 派生類與基類函數同名,並且參數相同,但是基類函數沒有virtual關鍵字,基類函數將被隱藏

7.虛函數與虛函數表相關知識點

多態是由虛函數實現的,而虛函數主要是通過虛函數表(V-Table)來實現的。

  • 類中若有virtual修飾的成員函數,該類就會有一個虛函數表
  • 該類定義的對象會有一個虛函數指針指向類的虛函數表,原始基類的對象的虛函數指針指向基類的虛函數表
  • 有純虛函數的類爲抽象類,不能被實例化。

8.C++中struct和class的區別

  • 默認繼承權限
  • 成員的默認訪問權限

  參考:https://blog.csdn.net/alidada_blog/article/details/83419757

9數組指針和指針數組

  • int (*ptr)[5],數組的指針相當於二維數組,也就是指針的指針
  • int *ptr[5],指針數組是一個數組,數組存放的元素爲指針

10.strlen和sizeof的區別

  • strlen是函數,在運行時才能計算,返回字符串的長度,必須以‘\0’結尾;sizeof是運算符,在編譯時就計算好了。

11.進程和線程

  • 進程是程序指令和相關資源的集合,是程序的運行實體,一個進程可以包含多個線程
  • 進程是資源分配的基本單位,線程是程序調度的基本單位,線程共享進程的資源(動態堆,靜態存儲區,代碼段),但是具有自己獨立的棧空間和寄存器
  • 進程的頻繁切換需要包含進程資源的保護和恢復動作,因此會引起多額外的開銷進而影響系統的性能,另外進程間的通信要求複雜的系統級實現,線程的切換比較快,容易實現併發,而且可以通過共享資源的方式進行多線程之間的通信,但是需要考慮同步的問題。

12.C/C++內存有哪幾種類型?

C中,內存分爲5個區:堆(malloc)、棧(如局部變量、函數參數)、程序代碼區(存放二進制代 碼)、全局/靜態存儲區(全局變量、static變量)和常量存儲區(常量)。此外,C++中有自由存儲區(new)一說。全局變量、static變量會初始化爲零,而堆和棧上的變量是隨機的,不確定的。

13.堆和棧的區別?

1).堆存放動態分配的對象——即那些在程序運行時分配的對象,比如局部變量,其生存期由程序控制;

2).棧用來保存定義在函數內的非static對象,僅在其定義的程序塊運行時才存在;

3).靜態內存用來保存static對象,類static數據成員以及定義在任何函數外部的變量,static對象在使用之前分配,程序結束時銷燬;

4).棧和靜態內存的對象由編譯器自動創建和銷燬。

 

14.什麼是內存泄漏?面對內存泄漏和指針越界,你有哪些方法?你通常採用哪些方法來避免和減少這類錯誤?

用動態存儲分配函數動態開闢的空間,在使用完畢後未釋放,結果導致一直佔據該內存單元即爲內存泄露。

 

1). 使用的時候要記得指針的長度.

2). malloc的時候得確定在那裏free.

3). 對指針賦值的時候應該注意被賦值指針需要不需要釋放.

4). 動態分配內存的指針最好不要再次賦值.

5). 在C++中應該優先考慮使用智能指針.

15. 函數調用的過程?

int main(void) { ... d = fun(a, b, c); cout<<d<<endl; ... return 0; }

調用fun()的過程大致如下:

main()========

1).參數拷貝(壓棧),注意順序是從右到左,即c-b-a;

2).保存d = fun(a, b, c)的下一條指令,即cout<<d<<endl(實際上是這條語句對應的彙編指令的起始位置);

3).跳轉到fun()函數,注意,到目前爲止,這些都是在main()中進行的;

fun()=====

4).移動ebp、esp形成新的棧幀結構;

5).壓棧(push)形成臨時變量並執行相關操作;

6).return一個值;

7).出棧(pop);

8).恢復main函數的棧幀結構;

9).返回main函數;

main()========

 

16. 左值和右值

https://blog.csdn.net/Tanswer_/article/details/77005674?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-3&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-3

17. int fun() 和 int fun(void)的區別?

這裏考察的是c 中的默認類型機制。

 

在c中,int fun() 會解讀爲返回值爲int(即使前面沒有int,也是如此,但是在c++中如果沒有返回類型將報錯),輸入類型和個數沒有限制, 而int fun(void)則限制輸入類型爲一個void。

在c++下,這兩種情況都會解讀爲返回int類型,輸入void類型。

18. 宏和內聯(inline)函數的比較?

1). 首先宏是C中引入的一種預處理功能;

2). 內聯(inline)函數是C++中引用的一個新的關鍵字;C++中推薦使用內聯函數來替代宏代碼片段;

3). 內聯函數將函數體直接擴展到調用內聯函數的地方,這樣減少了參數壓棧,跳轉,返回等過程;

4). 由於內聯發生在編譯階段,所以內聯相較宏,是有參數檢查和返回值檢查的,因此使用起來更爲安全;

5). 需要注意的是, inline會向編譯期提出內聯請求,但是是否內聯由編譯期決定(當然可以通過設置編譯器,強制使用內聯);

6). 由於內聯是一種優化方式,在某些情況下,即使沒有顯示的聲明內聯,比如定義在class內部的方法,編譯器也可能將其作爲內聯函數。

7). 內聯函數不能過於複雜,最初C++限定不能有任何形式的循環,不能有過多的條件判斷,不能對函數進行取地址操作等,但是現在的編譯器幾乎沒有什麼限制,基本都可以實現內聯。

19.C++中有了malloc / free , 爲什麼還需要 new / delete?

1). malloc與free是C++/C語言的標準庫函數,new/delete是C++的運算符。它們都可用於申請動態內存和釋放內存。

2). 對於非內部數據類型的對象而言,光用maloc/free無法滿足動態對象的要求。對象在創建的同時要自動執行構造函數,對象在消亡之前要自動執行析構函數。

由於malloc/free是庫函數而不是運算符,不在編譯器控制權限之內,不能夠把執行構造函數和析構函數的任務強加於malloc/free。因此C++語言需要一個能完成動態內存分配和初始化工作的運算符new,以一個能完成清理與釋放內存工作的運算符delete。注意new/delete不是庫函數。

最後補充一點體外話,new 在申請內存的時候就可以初始化(如下代碼), 而malloc是不允許的。另外,由於malloc是庫函數,需要相應的庫支持,因此某些簡易的平臺可能不支持,但是new就沒有這個問題了,因爲new是C++語言所自帶的運算符。

補充:

  • new是運算符,malloc()是一個庫函數;
  • new會調用構造函數,malloc不會;
  • new返回指定類型指針,malloc返回void*指針,需要強制類型轉換;
  • new會自動計算需分配的空間,malloc不行;
  • new可以被重載,malloc不能。

20.強制類型轉化

1).static_cast

a. 用於基本類型間的轉換

b. 不能用於基本類型指針間的轉換

c. 用於有繼承關係類對象間的轉換和類指針間的轉換

2). dynamic_cast

a. 用於有繼承關係的類指針間的轉換

b. 用於有交叉關係的類指針間的轉換

c. 具有類型檢查的功能

d. 需要虛函數的支持

3). reinterpret_cast

a. 用於指針間的類型轉換

b. 用於整數和指針間的類型轉換

4). const_cast

a. 用於去掉變量的const屬性

b. 轉換的目標類型必須是指針或者引用

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

C++語言支持函數重載,C語言不支持函數重載,函數被C++編譯器編譯後在庫中的名字與C語言的不同,假設某個函數原型爲:

 

void foo(int x, int y);

1

該函數被C編譯器編譯後在庫中的名字爲 _foo, 而C++編譯器則會產生像: _foo_int_int 之類的名字。爲了解決此類名字匹配的問題,C++提供了C鏈接交換指定符號 extern “C”。

22.頭文件中的 ifndef/define/endif 是幹什麼用的? 該用法和 program once 的區別?

相同點:

它們的作用是防止頭文件被重複包含。

不同點

1). ifndef 由語言本身提供支持,但是 program once 一般由編譯器提供支持,也就是說,有可能出現編譯器不支持的情況(主要是比較老的編譯器)。

2). 通常運行速度上 ifndef 一般慢於 program once,特別是在大型項目上, 區別會比較明顯,所以越來越多的編譯器開始支持 program once。

3). ifndef 作用於某一段被包含(define 和 endif 之間)的代碼, 而 program once 則是針對包含該語句的文件, 這也是爲什麼 program once 速度更快的原因。

4). 如果用 ifndef 包含某一段宏定義,當這個宏名字出現“撞車”時,可能會出現這個宏在程序中提示宏未定義的情況(在編寫大型程序時特性需要注意,因爲有很多程序員在同時寫代碼)。相反由於program once 針對整個文件, 因此它不存在宏名字“撞車”的情況, 但是如果某個頭文件被多次拷貝,program once 無法保證不被多次包含,因爲program once 是從物理上判斷是不是同一個頭文件,而不是從內容上。

23.說幾個C++11的新特性

24. 32位,64位系統中,各種常用內置數據類型佔用的字節數?

char :1個字節(固定)

*(即指針變量): 4個字節(32位機的尋址空間是4個字節。同理64位編譯器)(變化*)

short int : 2個字節(固定)

int: 4個字節(固定)

unsigned int : 4個字節(固定)

float: 4個字節(固定)

double: 8個字節(固定)

long: 4個字節

unsigned long: 4個字節(變化*,其實就是尋址控件的地址長度數值)

long long: 8個字節(固定)

 

64位操作系統

char :1個字節(固定)

*(即指針變量): 8個字節

short int : 2個字節(固定)

int: 4個字節(固定)

unsigned int : 4個字節(固定)

float: 4個字節(固定)

double: 8個字節(固定)

long: 8個字節

unsigned long: 8個字節(變化*其實就是尋址控件的地址長度數值)

long long: 8個字節(固定)

除*與long 不同其餘均相同。

25.virtual, inline, decltype,volatile,static, const關鍵字的作用?使用場景?

inline:在c/c++中,爲了解決一些頻繁調用的小函數大量消耗棧空間(棧內存)的問題,特別的引入了inline修飾符,表示爲內聯函數。

decltype:從表達式中推斷出要定義變量的類型,但卻不想用表達式的值去初始化變量。還有可能是函數的返回類型爲某表達式的的值類型。

volatile:volatile 關鍵字是一種類型修飾符,用它聲明的類型變量表示可以被某些編譯器未知的因素更改,比如:操作系統、硬件或者其它線程等。遇到這個關鍵字聲明的變量,編譯器對訪問該變量的代碼就不再進行優化,從而可以提供對特殊地址的穩定訪問。

static:

  1. 隱藏

      在變量和函數名前面如果未加static,則它們是全局可見的。加了static,就會對其它源文件隱藏,利用這一特性可以在不同的文件中定義同名函數和同名變量,而不必擔心命名衝  突。static可以用作函數和變量的前綴,對於函數來講,static的作用僅限於隱藏 。

    2.static變量中的記憶功能和全局生存期

26.深拷貝與淺拷貝的區別?

1.什麼時候用到拷貝函數?

  a.一個對象以值傳遞的方式傳入函數體; 

  b.一個對象以值傳遞的方式從函數返回;

  c.一個對象需要通過另外一個對象進行初始化。

  如果在類中沒有顯式地聲明一個拷貝構造函數,那麼,編譯器將會自動生成一個默認的拷貝構造函數,該構造函數完成對象之間的位拷貝。位拷貝又稱淺拷貝;

2.是否應該自定義拷貝函數?

 自定義拷貝構造函數是一種良好的編程風格,它可以阻止編譯器形成默認的拷貝構造函數,提高源碼效率。

3.什麼叫深拷貝?什麼是淺拷貝?兩者異同?

  如果一個類擁有資源,當這個類的對象發生複製過程的時候,資源重新分配,這個過程就是深拷貝,反之,沒有重新分配資源,就是淺拷貝。

4.深拷貝好還是淺拷貝好?

如果實行位拷貝,也就是把對象裏的值完全複製給另一個對象,如A=B。這時,如果B中有一個成員變量指針已經申請了內存,那A中的那個成員變量也指向同一塊內存。這就出現了問題:當B把內存釋放了(如:析構),這時A內的指針就是野指針了,出現運行錯誤。

27.計算類大小例子

class A {};: sizeof(A) = 1;

class A { virtual Fun(){} };: sizeof(A) = 4(32位機器)/8(64位機器);

class A { static int a; };: sizeof(A) = 1;

class A { int a; };: sizeof(A) = 4;

class A { static int a; int b; };: sizeof(A) = 4;

28.大端與小端的概念?各自的優勢是什麼?

  • 大端與小端是用來描述多字節數據在內存中的存放順序,即字節序。大端(Big Endian)指低地址端存放高位字節,小端(Little Endian)是指低地址端存放低位字節。
  • 需要記住計算機是以字節爲存儲單位。
  • 爲了方便記憶可把大端和小端稱作高尾端和低尾端,eg:如果是高尾端模式一個字符串“11223344”把尾部“44”放在地址的高位,如果是地尾端模式,把“44”放在地址的低位。

各自優勢:

  • Big Endian:符號位的判定固定爲第一個字節,容易判斷正負。
  • Little Endian:長度爲1,2,4字節的數,排列方式都是一樣的,數據類型轉換非常方便。

舉一個例子,比如數字0x12 34 56 78在內存中的表示形式爲:

  • 1)大端模式:

低地址 -----------------> 高地址

0x12 | 0x34 | 0x56 | 0x78

  • 2)小端模式:

低地址 ------------------> 高地址

0x78 | 0x56 | 0x34 | 0x12

29.C/C++中堆和棧的區別

講解全面的一篇博客:https://blog.csdn.net/Fiorna0314/article/details/49757195

鏈接1

鏈接2

30.指針常量與常量指針

常量指針(被指向的對象是常量)

定義:又叫常指針,可以理解爲常量的指針,指向的是個常量

關鍵點:

  1. 常量指針指向的對象不能通過這個指針來修改,可是仍然可以通過原來的聲明修改;
  2. 常量指針可以被賦值爲變量的地址,之所以叫常量指針,是限制了通過這個指針修改變量的值;
  3. 指針還可以指向別處,因爲指針本身只是個變量,可以指向任意地址;

const int *p或int const *p

(記憶技巧:const讀作常量,*讀作指針)

 

#include <stdio.h> // 常量指針(被指向的對象是常量) int main() { int i = 10; int i2 = 11; const int *p = &i; printf("%d\n", *p);//10 i = 9; //OK,仍然可以通過原來的聲明修改值, //Error,*p是const int的,不可修改,即常量指針不可修改其指向地址 //*p = 11; //error: assignment of read-only location ‘*p’ p = &i2;//OK,指針還可以指向別處,因爲指針只是個變量,可以隨意指向; printf("%d\n", *p);//11 return 0; }

 

指針常量(指針本身是常量)

定義:

本質是一個常量,而用指針修飾它。指針常量的值是指針,這個值因爲是常量,所以不能被賦值。

關鍵點:

  1. 它是個常量!
  2. 指針所保存的地址可以改變,然而指針所指向的值卻不可以改變;
  3. 指針本身是常量,指向的地址不可以變化,但是指向的地址所對應的內容可以變化;

int* const p;

 

//指針常量(指針本身是常量) #include <stdio.h> int main() { int i = 10; int *const p = &i; printf("%d\n", *p);//10 //Error,因爲p是const 指針,因此不能改變p指向的內容 //p++;//error: increment of read-only variable ‘p’ (*p)++; //OK,指針是常量,指向的地址不可以變化,但是指向的地址所對應的內容可以變化 printf("%d\n", *p);//11 i = 9;//OK,仍然可以通過原來的聲明修改值, return 0; }

 

31、函數模板與類模板有什麼區別?

【參考答案】

函數模板的實例化是由編譯程序在處理函數調用時自動完成的,而類模板的實例化必須由程序員在程序中顯式地指定。

32.智能指針

shared_ptr unique_ptr,weak_ptr,auto_ptr

https://blog.csdn.net/flowing_wind/article/details/81301001

https://blog.csdn.net/k346k346/article/details/81478223#1unique_ptr_4

參考:

https://blog.csdn.net/kuweicai/article/details/82779648

https://zhuanlan.zhihu.com/p/51918989

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章