1. 程式人生 > >2018秋招面試問題(二、C++基礎問題)

2018秋招面試問題(二、C++基礎問題)

目錄

智慧指標

c語言的程式碼段、資料段、bss段

編譯器在編譯程式的時候,將程式中的所有的元素分成了一些組成部分,各部分構成一個段,所以說段是可執行程式的組成部分。

程式碼段:程式碼段就是程式的可執行部分,直觀理解就是函式堆疊組成的。

資料段:資料段存放一些程式中的資料,初始化了的全域性變數、靜態變數都放在資料段。

bss段未初始化的全域性變數和靜態變數都放在bss段。

C++中為什麼空類的大小為1?為什麼成員函式不佔大小?為什麼有了成員變數之後就不用加1了?

  1. 被編譯器插進去的一個char ,使得這個class的不同實體(object)在記憶體中配置獨一無二的地址
    。 空類在例項化後會在記憶體得到了獨一無二的地址。
  2. 類中的靜態成員變數也是不佔類空間的,因為靜態屬於物件共享的,不為每個物件獨有。所以能計入物件大小(類空間的)都是物件所獨有的。類的所有物件都共用記憶體中同一份成員函式。每個物件通過把this指標以及其他引數傳遞方式來呼叫成員函式。
  3. 在有成員變數之後,物件例項化就可以通過不同成員來得到不同的記憶體地址,就不需要那個標識地址不同的char了。

如何理解面向物件(oop)

面向物件有三大特性,封裝、繼承和多型。

封裝就是將一類事物的屬性和行為抽象成一個類,使其屬性私有化,行為公開化,提高了資料的隱祕性的同時,使程式碼模組化。這樣做使得程式碼的複用性

更高。

繼承就是一個類繼承另一個類,實現了程式碼的複用,繼承後子類自動擁有了父類的屬性和方法,子類也可以寫自己特有的屬性和方法,目的是實現功能的擴充套件。

多型就是呼叫相同的方法,引數也相同時,但表現的行為卻不同,這是由虛擬函式來實現的。

面向過程程式設計、OOP面向物件程式設計和泛型程式設計

面向過程是一種以過程為中心的程式設計思想,考慮的是實際的實現過程,比如說c語言,以函式作為基本單元,就是通過函式來體現的。OOP是面向物件程式設計,把物件作為程式的基本單元,一個物件包含了資料和操作資料的函式,通過封裝、繼承、多型來實現程式。

C++中還包括過載、多型、繼承、輸入輸出流這些。

泛型程式設計就是提供了模板,將型別引數化,用template <typename T>,

比如STL容器,都屬於泛型程式設計,其中的型別可變。

typedef的作用

第一,定義別名。可以定義一種型別的別名,也可以替複雜宣告定義一個別名。可以用來同時宣告多個指標。比如char* a,b;只是定義了一個指標和一個變數。如果有typedef char* PCHAR;就可以連續定義多個指標,PCHAR a,b,c,d; 和char*a,*b是等價的。typedef更直觀。

第二,在結構體中用來省略struct

typedef struct ListNode

{

struct ListNode *next;

int val;

}ListNode;

比如連結串列的結構體,ListNode就代替struct ListNode

第三,可以用來定義與平臺有關的資料型別。當跨平臺的時候,只需要修改typedef就行了。

關於typedef的注意點

  • typedef是定義了一種型別的新別名,不同於巨集,不是簡單的字串替換。比如:

typedef char* PSTR;

const PTSR p = “abc”;//這個地方const限制了p只讀

p++;//錯誤×

記住const和 typedef一起出現時,絕不是簡單的字元替換

  • typedef是一個儲存型別的關鍵字(同auto、extern、mutable、static、register等一樣),雖然它實際上不影響物件的儲存特性。所以要注意不能和別的儲存型別同時使用。

typedef static int INT;//會報錯

斷言assert瞭解嗎?

assert是一個巨集,相當於一個if語句,在debug模式下使用的,assert中的表示式為真,程式正常執行,表示式為假,就會終止程式。頻繁地呼叫assert會影響程式的效能。禁用assert,就是在include後面加#define NDEBUG。

#include#define NDEBUG #include

靜態區域性變數、靜態全域性變數、普通全域性變數之間的區別

首先它們都存在記憶體的全域性儲存區。

一個程式由多個原始檔組成。這三種變數的生命期都是整個程式。

靜態區域性變數的作用域是定義它的那個函式內部,且只能初始化一次。

靜態全域性變數的作用域是整個原始檔,不可extern到別的原始檔中使用。

普通全域性變數的作用域是整個原始檔,但是可以extern到別的原始檔中使用。

fopen文字模式和二進位制模式的區別

FILE * fopen(const char * path,const char * mode);

首先文字檔案是基於字元編碼的檔案,如ASCII碼、Unicode等,包括xml檔案、html超文字檔案、c源程式檔案等。二進位制檔案是基於值編碼的檔案,如word檔案、影象格式檔案JPG等。

fopen中二進位制模式是原封不動的讀寫檔案的全部內容。

文字模式下,你寫進去、讀出來的,和實際儲存的資料,兩者不一定相同;

二進位制模式下,你寫進去、讀出來的,和實際儲存的資料,兩者一定相同。

以文字方式開啟檔案的話,當讀取檔案的時候,系統會將所有的"/r/n"(回車換行)轉換成"/n"(換行);當寫入檔案的時候,系統會將"/n"轉換成"/r/n"寫入。

r 開啟只讀檔案,該檔案必須存在。

r+ 開啟可讀寫的檔案,該檔案必須存在。

rb+ 讀寫開啟一個二進位制檔案,只允許讀寫資料。

rt+ 讀寫開啟一個文字檔案,允許讀和寫。

w 開啟只寫檔案,若檔案存在則檔案長度清為0,即該檔案內容會消失。若檔案不存在則建立該檔案

w+ 開啟可讀寫檔案,若檔案存在則檔案長度清為零,即該檔案內容會消失。若檔案不存在則建立該檔案。

wb 只寫開啟或新建一個二進位制檔案;只允許寫資料。

wb+ 讀寫開啟或建立一個二進位制檔案,允許讀和寫。

wt+ 讀寫開啟或著建立一個文字檔案;允許讀寫。

有 + 表示允許讀寫。

wb+和rb+都可以進行讀寫,區別在於wb+可以開啟或者建立一個檔案。

對C++頂層const和底層const的區別

對於普通變數沒有頂層底層的區別,對於指標來說才有區別。

頂層const指的是常量指標,也就是指標本身不可改變。*const

底層const指的是指向常量的指標,也就是指標指向的值不可改變。const* 就是底層。

C++11有沒有了解過?

C++11C++程式語言的一個標準,之前的標準有C++98以及C++03。相比於C++03,C++11標準包含核心語言的新機能,而且擴充套件C++標準程式庫。

例如:

for迴圈使用更簡單

引入了空指標nullptr解決NULL二義性

void foo(int n);

void foo(char* cArr);

上面聲明瞭兩個過載函式,當我呼叫foo(NULL),編譯器將會呼叫foo(int)函式,而實際上我是想呼叫foo(char*)函式的。為了避免這個歧義,C++11重新定義了一個新關鍵字nullptr,充當單獨空指標常量。

引入了 auto 和 decltype 這兩個關鍵字實現了型別推導,auto推導變數,decltype推導表示式。

auto會忽略掉頂層const,保留底層const。

const int i = 5;

auto a = i; //a是int型別而不是const int

const auto a = i;//a就是才是const int型

引入了智慧指標

智慧指標

智慧指標是對普通指標增加了一層封裝機制,用來方便地管理一個物件的生命週期(及物件什麼時候被刪除或被析構由智慧指標本身決定,不需要使用者管理)

智慧指標的作用:智慧指標是為了避免記憶體洩露的問題,替代了new和delete。

關鍵字auto_ptr、unique_ptr、shared_ptr和weak_ptr,標頭檔案是<memory>。其中auto_ptr是c++98中的,c++11將其拋棄,是為了避免潛在的記憶體崩潰的問題(當兩個指標指向同一個記憶體的時候,會釋放兩次),替換為unique_ptr、shared_ptr則不會崩潰。unique_ptr會在編譯時就報錯,而shared_ptr則會計算引用的次數,就不會出現多次刪除。

auto_ptr<int> m (new int(5));

如果shared_ptr的兩個指標b賦值給a,則兩個指標的計數值都會增加。shared_ptr指標的計數值指的是指向這塊記憶體的指標個數。

shared_ptr的計數機制

建構函式中計數初始化為1;

拷貝建構函式中計數值加1;

賦值運算子中左邊的引用物件計數-1,右邊的引用物件技術+1;

解構函式中引用計數-1,當減為0,就會自動delete釋放掉物件空間。

C++的記憶體分配\記憶體管理方式

C++中,記憶體區分為五個區,分別是堆、棧、全域性儲存區、常量儲存區、自由儲存區。

常量儲存區:常量字串等;

全域性儲存區:全域性變數、靜態變數,程式結束後由系統釋放。

棧區:區域性變數、函式的引數變數,由編譯器自動分配釋放(棧地址是向下增長的)。

堆區:由程式設計師分配釋放,malloc在堆上分配的記憶體塊,使用free釋放記憶體。

自由儲存區:是通過new和delete動態分配和釋放物件的抽象概念,new所申請的記憶體區域在c++中稱為自由儲存區。

C的記憶體管理方式

堆、棧、全域性區、常量區。

自由儲存區和堆是兩塊不同的記憶體區域嗎?它們有可能相同嗎?

自由儲存區和堆是兩個不同的概念,它們有可能指向同一塊記憶體區域。

基本上,所有的C++編譯器預設使用堆來實現自由儲存,也就是new和delete也許會按照malloc和free的方式來被實現,這時藉由new運算子分配的物件,說它在堆上也對,說它在自由儲存區上也正確,這時候他們就是相同的記憶體。而如果程式設計師也可以通過過載操作符,改用其他記憶體來實現自由儲存,例如全域性變數做的物件池,這時自由儲存區就區別於堆了,這時候就是不同的記憶體區域。