1,變量的聲明和定義有什么區別。
聲明不分配內存,定義分配內存。變量只能被定義一次,但可以被聲明多次。
// 定義 int i; // 聲明 extern int i; // 定義(對資源進行了初始化) extern int i = 1;
2,#ifdef、#else、#endif和#ifndef的作用。
預處理條件命令。根據宏定義選擇要編譯的代碼塊。
3,寫出bool、 float
、指針變量與 “零值 ”比較的if
語句
// float if ((f >= -0.000001) && (f <= 0.000001))){} // ptr if(p == nullptr){}
4,結構體可以直接賦值嗎。
同類型之間可以。結構體內有裸指針需要注意相當於多個指針指向同塊內存。
5,sizeof
和strlen
的區別
sizeof 是關鍵字、運算符,strlen 是庫函數。
sizeof 返回的是內存大小。結果是編譯時計算。參數可以是類型。
strlen 返回的是字符串長度且不包括null結束符。結果是運行時計算。參數只能是 char* 且必須以 '/0' 結尾。
6,static 關鍵字的作用
1,static 用來修飾【靜態的】全局、局部 的 變量、函數。
2,被 static 修飾的變量或函數,內存空間存儲於靜態(全局)存儲區,生命周期伴隨整個程序生命周期。
3,此外還用來定義類靜態類成員變量、函數。靜態成員是屬於整個類的而不是某個對象,靜態成員變量只存儲一份供所有對象共用。所以在所有對象中都可以共享它。使用靜態成員變量實現多個對象之間的數據共享 不會破壞隱藏的原則,保證了安全性還可以節省內存。
4,靜態局部變量在程序執行到該對象的聲明處時被首次初始化,即以后的函數調用不再進行初始化;
5,靜態局部變量一般在聲明處初始化,如果沒有顯式初始化,會被程序自動初始化為 0;
6,全局靜態變量是顯式用 static 修飾的全局變量,作用域是聲明此變量所在的文件,其他的文件即使用 extern 聲明也不能使用。
7,C 語言的malloc
和 C++ 中的new
有什么區別
malloc 與 Free 是函數。new 與 delete 是C++關鍵字。
malloc 與 Free 不會調用構造、析構函數,僅僅是分配釋放內存。new 與 delete 會調用構造、析構函數並分配或釋放內存。
malloc 返回的是 void* 類型指針。new 返回的是帶有類型的指針。
new 和 delete 在 C++ 中可以重載。
8,++i 和 i++ 的區別
++i 是先自增再賦值,先在局部變量自增再壓棧。
i++ 是先賦值再自增,先壓棧再在局部變量表中賦值。
++i 可以作為左值,i++則不行。
9,volatile 有什么作用
volatile 是指令關鍵字,確保本條指令不會因編譯器的優化而省略,且要求每次直接讀值。也就是不在CPU寄存器當中讀取,每次都要重新從內存當中讀取。
10, 一個參數可以既是const
又是volatile
嗎
可以。
11,全局變量和局部變量的區別:
1,作用域不同、生命周期不同。
2,內存存儲區域不同,全局變量存儲於全局數據區,局部變量存儲於棧區。
12,++i 和 i++區別
++i 是先自增后壓棧。
i++ 先壓入臨時變量表,再在臨時變量表中進行自增操作。
++i 可以作為左值,i++ 不行。
13,volatile
有什么作用
修飾某個變量,當讀取該變量時,需要再次從內存中讀取,而不是CPU寄存器當中。
可以和 const 結合使用。
14,全局變量和局部變量有什么區別?
1,生命周期不同、作用域不同。
2,內存存儲空間不同,局部變量位於棧區,全局變量位於全局(靜態)存儲區。
15,簡述 C、C++ 程序編譯的內存分配情況
1,棧區:存放局部變量、函數參數傳遞的臨時變量。
2,堆區:由程序執行動態分配,需要手動管理、容量大的內存區域。
3,常量池:存放常量的區域。
4,全局\靜態區:存放全局變量及靜態變量。
5,代碼塊
16,簡述strcpy、sprintf
與memcpy
的區別
strcpy: 拷貝字符串從源地址到目標地址
memcpy: 拷貝內存塊
sprintf: 本意是字符串格式化,將源字符串格式化拷貝到目標地址。
17,指針和引用的區別
相同點:都是基於地址的概念,指針是存儲某塊內存的地址,引用是某塊內存的別名。
不同點:1,指針是實體,是變量。引用只是一個別名。
2,引用定義必須初始化且只能初始化一次,不能為空,且不可被改變。
3,sizeof 引用是獲取的它所指向對象的大小,指針是指針變量本身的大小。
4,指針可以多級,引用只能一級。
18,typedef
和define
有什么區別?
typedef 是為變量定義別名,#defind是定義宏常量。
typedef 是運行時,#defind是編譯時預處理指令。
typedef 有作用域,#defind 沒有。
19,指針常量與常量指針區別?(中華語言博大精深)
int* const p;
指針常量:固定指向一塊內存的指針,因為是常量所以值無法修改。
int const* p; const int* p;
常量指針:指向一個常量的指針。
20, 簡述隊列和棧的異同
共同點:都是線性表,都是在端點插入刪除。
異同點:棧是先進后出,只能在一端修改(棧頂)。隊列是隊頭插入、隊尾刪除,先進先出。
21,在C++中結構體與類的不同:
結構體對成員默認是public ,類默認是private。
22,句柄和指針的區別和聯系是什么?
完全沒有聯系。
句柄是 Windows 系統標記資源的一種方式,類型是32位的unit。
指針是指向一塊內存的變量。
23,extern“C”的作用:
extern "C"的主要作用就是為了能夠正確實現C++代碼調用其他C語言代碼。加上extern "C"后,會指示編譯器這部分代碼按C語言的進行編譯,而不是C++的。由於C++支持函數重載,因此編譯器編譯函數的過程中會將函數的參數類型也加到編譯后的代碼中,而不僅僅是函數名;而C語言並不支持函數重載,因此編譯C語言代碼的函數時不會帶上函數的參數類型,一般只包括函數名。
24,C++ 類內可以定義引用數據成員嗎?
可以,但是要在對象創建之時就初始化,也就意味着不能用空默認構造函數進行初始化。並且,構造函數參數必須也是同引用類型且必須在初始化表中初始化。
25,C++ 中類成員的訪問權限及繼承方式異同:
public 公有成員 :基類、派生類、友元、外部都可以訪問
protected 保護成員: 基類、派生類、友元可以訪問
private 私有成員 :基類、友元可以訪問
繼承方式 | 基類 public 成員 | 基類 protected 成員 | 基類 private 成員 |
public | public | protected | private |
protected | protected | protected | private |
privat | privat | private | private |
26,什么是右值引用,跟左值又有什么區別?
1、消除兩個對象交互式時,不必要的拷貝,節省資源,提高效率;
2、簡潔定義泛型函數;
左值:能取地址,或者具名對象,表達式結束后依然存在的持久對象;
右值:不能取地址,匿名對象,表達式結束后就不再存在的臨時對象;
左值能尋址,右值不能;
左值能賦值,右值不能;
27, 用 C++ 設計一個不能被繼承的類:
使用final關鍵字。
28,訪問基類的私有虛函數
把問這個問題的人揍一頓。這種行為是卡編譯器BUG。
29, 對虛函數和多態的理解
https://www.airchip.org.cn/index.php/2022/02/11/cpp-example-interface/
30,重寫和重載的區別:
重載:返回值類型相同 函數名相同 參數不同
重寫:子類覆寫父類函數,返回值類型相同 函數名相同 參數相同,實現不同。
31,vector
中的reserve
和resize
的區別
reserve:重新分配堆內存空間
resize:修改長度,但不回收空間。
32, vector中的
size和
capacity的區別
size() (大小)指容器當前擁有元素的個數;
capacity() (容量)指容器在必須分配存儲空間之前可以存儲元素的總數(已用內存單元,單元大小由類型而定);
33,vector中erase方法與algorithm中的remove方法區別
erase刪除一個元素后,相對應的元素被刪除,並且容器中的元素也隨之減少了一個,迭代器不能訪問。
調用algorithm中的remove刪除后相對應的元素被刪除,但是容器中的元素個數沒有變少,並且刪除后容器后面的元素往前移動一個位置,並且最后的元素的值,是用之前最后一個元素的值填充。並且remove返回的迭代器位置是最后一個元素的位置。
34,正確釋放vector
的內存
https://www.airchip.org.cn/index.php/2021/12/12/examplecvectordncqzhs/
35,什么情況下用vector,什么情況下用list,什么情況下用 deque
vector: 對象在內存中連續存儲,隨機訪問性能高。(老頭子說需要容器找它就對了)
list:對象在內存中分散存儲,適合頻繁寫入修改,頭插和尾插性能最高
deque: 合並了以上兩者,連續空間存儲的list,隨機訪問、雙端修改性能好。但是資源消耗大,適合頻繁增刪改查的場景。
36,為何map和set的插入刪除效率比其他序列容器高
MAP的節點是一對數據. SET的節點是一個數據.不需要內存的移動和拷貝。
37,為何map
和set
每次Insert
之后,以前保存的iterator
不會失效
因為每次插入刪除會動態開辟釋放內存空間,只有當前變化的節點iterator失效,之前保存的iterator由於內存空間未發生變化所以並不會失效。
38.map能不能邊遍歷邊刪除?
不可以,因為map刪除了一個元素之后該元素對應節點的迭代器失效,且erase並不返回下一個元素的迭代器。
39,為何map
和set
每次Insert
之后,以前保存的iterator
不會失效?
在map和set當中, 迭代器相當於指向節點的指針。
40,為何map
和set
不能像vector
一樣有個reserve
函數來預分配數據
原因在於在map和set內部存儲的已經不是元素本身了,而是包含元素的節點。
41,hash_map
與map
的區別?什么時候用hash_map
,什么時候用map
1、STL的map底層是用紅黑樹實現的,查找時間復雜度是log(n);
2、STL的hash_map底層是用hash表存儲的,查詢時間復雜度是O(1);
hash_map 查找速度會比map快,而且查找速度基本和數據量大小無關,屬於常數級別;而map的查找速度是log(n)級別。並不一定常數就比log(n) 小,hash還有hash函數的耗時。
42,static函數與普通函數有什么區別?
static 修飾的函數只能在當前代碼文件中訪問,並且會被分配到內存的靜態區,整個生命周期只有一份。
43,在C語言中,為什么 static變量只初始化一次?
因為Static會被分配到內存的靜態區,且在程序生命周期當中只有一份。
44,為什么基類的析構函數必須是虛函數?
1.析構函數不一定必須是虛函數,是否為虛函數取決於該類的使用,一般該類為基類產生繼承和多態時,才會是虛函數,單獨使用可以不是虛函數。之所以在繼承和多態時設計為虛函數是因為當new派生類並且用基類指針指向這個派生類,在銷毀基類指針時只會調用基類的析構函數,不會調用派生類的析構函數,因為基類無法操作派生類中非繼承的成員,這樣就造成派生類只new無法delete造成內存泄露。 2.默認不是虛析構函數是因為如果析構函數為虛函數就需要編譯器在類中增加虛函數表來實現虛函數機制,這樣所需內存空間就更大了,因此沒有必要默認為虛析構函數。