C/C++ 面试题记录
1、new 、 delete 、 malloc 、 free?的區別與關系?
new / delete?是C++的運算符,malloc / free?是C的標準庫函數。
new會調用對象的構造函數,delete會調用對象的析構函數。它們都可用于動態申請內存和釋放內存。
對于非內部數據類型的對象而言,使用malloc / free?無法滿足動態對象的要求,對象在創建的時候要自動執行構造函數,在銷毀時要自動執行析構函數。
由于malloc/free是庫函數而不是運算符,不在編譯器控制權限之內,不能夠把執行構造函數和析構函數的任務強加于malloc/free。
2、C++是不是安全類型的?
不是;兩個不同類型的指針之間可以相互轉換(reinterpret cast)。 C#?是安全類型的。
3、const 作用,const?與 #define?相比有何優點?
const?作用:?定義常量、修飾函數參數、修飾函數返回值。被const修飾的東西都受到強制保護,可以防止意外的修改。
const常量具有數據類型,而宏常量沒有數據類型。編譯器可以對const常量進行類型安全檢查,而#define只是進行字符替換,沒有類型安全檢查。
有些集成的調試工具可以對const常量進行調試,但不能對宏定義進行調試。
1.const 修飾類的成員變量,表示成員常量,不能被修改。
2.const修飾函數承諾在本函數內部不會修改類內的數據成員,不會調用其它非 const 成員函數。
3.如果 const 構成函數重載,const 對象只能調用 const 函數,非 const 對象優先調用非 const 函數。
4.const 函數只能調用 const 函數。非 const 函數可以調用 const 函數。
5.類體外定義的 const 成員函數,在定義和聲明處都需要 const 修飾符。
3、Static?的作用?
類的靜態成員變量在類實例化之前就已經存在了,并且分配了內存。函數的static變量在執行此函數時進行初始化。
1.? 函數體內 static 變量的作用范圍為該函數體,不同于 auto 變量, 該變量的內存只被分配一次,因此其值在下次調用時仍維持上次的值。
2.??在模塊內的 static 全局變量可以被模塊內所有函數訪問,但不能被模塊外其他函數訪問。
3.??在模塊內的static 函數只可被這一模塊內的其他函數調用,這個函數的使用范圍被限制在聲明它的模塊內。
4.? 在類的static 成員變量屬于整個類所擁有,對類的所以對象只有一份拷貝。
5. 在類中的 static 成員函數屬于整個類所擁有,這個函數不接收 this 指針,因而只能訪問類的 static 成員變量。
最重要的一條:隱藏。(static函數,static變量均可
? ? ? ? 當同時編譯多個文件時,所有未加static前綴的全局變量和函數都具有全局可見性。?如果加了static,就會對其它源文件隱藏。
3:解釋C++中靜態函數和靜態變量?
(1)類靜態數據成員在編譯時創建并初始化:在該類的任何對象建立之前就存在,不屬于任何對象,而非靜態類成員變量則是屬于對象所有的。類靜態數據成員只有一個拷貝,為所有此類的對象所共享。
(2)類靜態成員函數屬于整個類,不屬于某個對象,由該類所有對象共享。
1.? static 成員變量實現了同類對象間信息共享。
2.? static 成員類外存儲,求類大小,并不包含在內。
3.? static 成員是命名空間屬于類的全局變量,存儲在 data 區的rw段。
4.? static 成員只能類外初始化。
5.? 可以通過類名訪問(無對象生成時亦可),也可以通過對象訪問。
a.? 靜態成員函數的意義,不在于信息共享,數據溝通,而在于管理靜態數據成員,完成對靜態數據成員的封裝。
b.? 靜態成員函數只能訪問靜態數據成員。原因:非靜態成員函數,在調用時 this指針時被當作參數傳進。而靜態成員函數屬于類,而不屬于對象,沒有 this 指針。
4、引用與指針的區別?
1.引用必須被初始化,指針不需要。
2.引用初始化以后不能修改,指針可以改變其所指的對象。
3.不存在指向空值的引用,但存在指向空值的指針。
? ? ? ?4.引用沒有 const,指針有 const;
5.引用變量內存單元保存的是被引用變量的地址。
? ? ? ?6.“sizeof 引用" = 指向變量的大小 , "sizeof 指針"= 指針本身的大小。
7.引用可以取地址操作,返回的是被引用變量本身所在的內存單元地址。
8.指針和引用的自增(++)運算意義不一樣;
8. 指針可以有多級,但是引用只能是一級(int **p;合法 而 int &&a是不合法的)
9.從內存分配上看:程序為指針變量分配內存區域,而引用不需要分配內存區域。
5、?成員函數通過什么來區分不同對象的成員數據?為什么能夠區分?
通過this指針,?因為它指向的是對象的首地址。
6、什么時候必須重新拷貝構造函數?
當構造函數涉及到動態存儲分配空間的時候,要自己編寫拷貝構造函數,并且要深拷貝。
7、靜態函數存在的意義?
靜態私有成員在類外不能被訪問,只能通過類的靜態成員函數來訪問。
7、在c++程序中調用被C編譯器編譯后的函數,為什么要加extern“C”?
?????C++語言支持函數重載,C語言不支持函數重載,函數被C++編譯器編譯后在庫中的名字與C語言的不同,
8、不允許重載的5個運算符?
.*(成員指針訪問運算符)、 ::(域運算符)、?sizeof 、 ? : 、 .(成員訪問符)
一、堆棧空間分配區別:
1、棧(操作系統):由操作系統自動分配釋放 ,存放函數的參數值,局部變量的值等。其操作方式類似于數據結構中的棧;
2、堆(操作系統): 一般由程序員分配釋放, 若程序員不釋放,程序結束時可能由OS回收,分配方式倒是類似于鏈表。
二、堆棧緩存方式區別:
1、棧使用的是一級緩存, 他們通常都是被調用時處于存儲空間中,調用完畢立即釋放;
2、堆是存放在二級緩存中,生命周期由虛擬機的垃圾回收算法來決定(并不是一旦成為孤兒對象就能被回收)。所以調用這些對象的速度要相對來得低一些。
三、堆棧數據結構區別:
堆(數據結構):堆可以被看成是一棵樹,如:堆排序;
棧(數據結構):一種先進后出的數據結構。
9、流運算符為什么不能通過類的成員函數重載?一般怎么解決?
因為通過類的成員函數重載要求運算符的第一個操作數必須是自己,?而流運算符重載要求第一個操作數是流對象。一般通過友元來解決。
10、對象間是怎樣實現數據的共享的?
通過類的靜態成員變量來實現的。靜態成員變量占有自己獨立的空間不為某個對象所私有。
11、友元關系有什么特性?
單向的,非傳遞的,不能繼承的。
12、const char *p, char * ?const p;的區別
如果const位于星號的左側,則const就是用來修飾指針所指向的變量,即指針指向為常量;
如果const位于星號的右側,const就是修飾指針本身,即指針本身是常量。
13、繼承優缺點。
1、類繼承是在編譯時刻靜態定義的,且可直接使用,
2、類繼承可以較方便地改變父類的實現。
缺點:
1、因為繼承在編譯時刻就定義了,所以無法在運行時刻改變從父類繼承的實現
2、父類通常至少定義了子類的部分行為,父類的任何改變都可能影響子類的行為
3、如果繼承下來的實現不適合解決新的問題,則父類必須重寫或被其他更適合的類替換。這種依賴關系限制了靈活性并最終限制了復用性。
14、多態的作用?
1.隱藏實現細節,使得代碼能夠模塊化;擴展代碼模塊,實現代碼重用。
2.接口重用:為了類在繼承和派生的時候,保證使用家族中任一類的實例的某一屬性時的正確調用。
15、析構函數為什么要虛擬?
為了防止析構不徹底造成內存泄漏
15、什么時候要用虛析構函數
?????? 通過基類的指針來刪除派生類的對象時,基類的析構函數應該是虛的。否則其刪除效果將無法實現。
?????? 一般情況下,這樣的刪除只能夠刪除基類對象,而不能刪除子類對象,形成了刪除一半形象,從而千萬內存泄漏。
????? 原因:
????????????? 在公有繼承中,基類對派生類及其對象的操作,只能影響到那些從基類繼承下來的成員。
????????????? 如果想要用基類對非繼承成員進行操作,則要把基類的這個操作(函數)定義為虛函數。
????????????? 那么,析構函數自然也應該如此:如果它想析構子類中的重新定義或新的成員及對象,當然也應該聲明為虛的。
????? 注意:如果不需要基類對派生類及對象進行操作,則不能定義虛函數(包括虛析構函數),因為這樣會增加內存開銷。
15、C++怎樣讓返回對象的函數不調用拷貝構造函數
拷貝構造函數前加"explict"關鍵字。
16、如何引用一個已經定義過的全局變量?
可以用引用頭文件的方式,也可以用extern關鍵字,如果用引用頭文件方式來引用某個在頭文件中聲明的全局變理,假定你將那個變寫錯了,那么在編譯期間會報錯,如果你用extern方式引用時,假定你犯了同樣的錯誤,那么在編譯期間不會報錯,而在連接期間報錯。
17、用什么函數開啟新進程、線程。
線程:CreateThread/AfxBeginThread等
進程:CreateProcess等
18、strcpy()和memcpy()的區別?
strcpy()和memcpy()都可以用來拷貝字符串,strcpy()拷貝以’\0’結束,但memcpy()必須指定拷貝的長度。
19、總結static的應用和作用?
(1)函數體內static變量的作用范圍為該函數體,不同于auto變量,該變量的內存只被分配一次,因此其值在下次調用時仍維持上次的值;
(2)在模塊內的static全局變量可以被模塊內所用函數訪問,但不能被模塊外其它函數訪問;
(3)在模塊內的static函數只可被這一模塊內的其它函數調用,這個函數的使用范圍被限制在聲明它的模塊內;
(4)在類中的static成員變量屬于整個類所擁有,對類的所有對象只有一份拷貝;
(5)在類中的static成員函數屬于整個類所擁有,這個函數不接收this指針,因而只能訪問類的static成員變量。
20、struct(結構) 和 union(聯合)的區別?
1. 結構和聯合都是由多個不同的數據類型成員組成, 但在任何同一時刻, 聯合中只存放了一個被選中的成員(所有成員共用一塊地址空間), 而結構的所有成員都存在(不同成員的存放地址不同)。
2. 對于聯合的不同成員賦值, 將會對其它成員重寫, ?原來成員的值就不存在了, 而對于結構的不同成員賦值是互不影響的。
21、windows消息系統由哪幾部分構成?
1.消息隊列:操作系統負責為進程維護一個消息隊列;程序運行時不斷的從該消息隊列中獲取消息、處理消息。
2.消息循環:應用程序通過消息循環不斷地獲取消息、處理消息。
3.消息處理:消息循環負責將消息派發到相關的窗口上使用關聯的窗口過程函數進行處理。
22、winsock建立連接的主要實現步驟?
服務器端:socket()建立套接字,綁定(bind)并監聽(listen),用accept()等待客戶端連接, accept()發現有客戶端連接,建立一個新的套接字,自身重新開始等待連接。該新產生的套接字使用send()和recv()寫讀數據,直至數據交換完畢,closesocket()關閉套接字。
客戶端:socket()建立套接字,連接(connect)服務器,連接上后使用send()和recv(),在套接字上寫讀數據,直至數據交換完畢,closesocket()關閉套接字。
?23、進程間通信的主要方式
信號、信號量、管道、有名管道、消息、共享內存、套接字、文件
?24、線程同步的方式
?????Linux:???互斥鎖、條件變量和信號量
24、多線程同步和互斥有幾種實現方法,都是什么?
線程間的同步方法大體可分為兩類:用戶模式和內核模式。顧名思義,內核模式就是指利用系統內核對象的單一性來進行同步,
使用時需要切換內核態與用戶態,而用戶模式就是不需要切換到內核態,只在用戶態完成操作。
用戶模式下的方法有:原子操作(例如一個單一的全局變量),臨界區。內核模式下的方法有:事件,信號量,互斥量。
24、多線程同步和互斥有何異同,在什么情況下分別使用他們?舉例說明。
線程同步是指線程之間所具有的一種制約關系,一個線程的執行依賴另一個線程的消息,當它沒有得到另一個線程的消息時應等待,直到消息到達時才被喚醒。
線程互斥是指對于共享的進程系統資源,在各單個線程訪問時的排它性。當有若干個線程都要使用某一共享資源時,任何時刻最多只允許一個線程去使用,其它要使用該資源的線程必須等待,直到占用資源者釋放該資源。線程互斥可以看成是一種特殊的線程同步。
24、構成Win32 API 函數的三個動態鏈接庫是什么?
內核庫,用戶界面管理庫,圖形設備界面庫。
25、windows消息分為幾類?并對各類做簡單描述。
1.窗口消息:與窗口相關的消息,除WM_COMMAND之外的所有以WM_開頭的消息;
2.命令消息;用于處理用戶請求,以WM_COMMAND表示的消息;
3.控件通知消息:統一由WM_NOTIFY表示,
4.用戶自定義消息。(WM_USER 、?WM_APP)
26、MFC中,大部分類是從哪個類繼承而來?
CObject
27、TCP/IP 建立連接的過程
在TCP/IP協議中,TCP協議提供可靠的連接服務,采用三次握手建立一個連接。.TCP是基于流的,UDP基于數據報文
第一次握手:建立連接時,客戶端發送連接請求到服務器,并進入SYN_SEND狀態,等待服務器確認;
第二次握手:服務器收到客戶端連接請求,向客戶端發送允許連接應答,此時服務器進入SYN_RECV狀態;
第三次握手:客戶端收到服務器的允許連接應答,向服務器發送確認,客戶端和服務器進入通信狀態,完成三次握手
28、memset ,memcpy 的區別
memset用來對一段內存空間全部設置為某個字符,一般用在對定義的字符串進行初始化為'\0'。
memcpy用來做內存拷貝,你可以拿它拷貝任何數據類型的對象,可以指定拷貝的數據長度。
29、實現memcpy(),?完成內存之間的拷貝。
void *memcpy(void *dest, const void *src, size_t count)
{
char *pDest = static_cast<char *>(dest);
const char *pSrc = static_cast<char *>(src);
if (pDest>pSrc && pDest < pSrc+count)
{
for(size_t i = count-1; i >= 0; i--)
pDest[i] = pSrc[i];
} else {
for(size_t i = 0; i < count; i++)
pDest[i] = pSrc[i];
}
return dest;
}
30、已知strcpy函數的原型是:?char * strcpy(char * strDest,const char * strSrc);不調用庫函數,實現strcpy函數。
char *strcpy(char *strDest, const char *strSrc)
{?
if (strDest == NULL || strSrc == NULL)
return NULL;
if (strDest == strSrc)
return strSrc;
char *tempPtr = strDest;
while ((*strDest = *strSrc) != '\0');
return tempPtr;
}
31、已知類String 的原型為:
class String
{
public:
String(const char *str = NULL); // 普通構造函數
String(const String &other); // 拷貝構造函數
~ String(void); // 析構函數
String & operate =(const String &other); // 賦值函數
private:
char *m_data; // 用于保存字符串
};
String (const char *str = NULL)? ? //?構造函數
{
if (str == NULL)?{? ??//strlen在參數為NULL時會拋異常才會有這步判斷
m_data = new char[1];
m_data[0] = '';
}? else? {
m_data = new char[strlen(str) + 1];
strcpy(m_data, str);? ?
}
}
String (const String & other)? ?//?拷貝構造
{
m_data = new char[strlen(other.m_data) + 1];
strcpy(m_data, other.m_data);
}
String & String::operator =(const String & other)? ?//?賦值重載
{
if (this == &other)
return *this;
delete []m_data;
m_data = new char[strlen(other.m_data) + 1];
strcpy(m_data, othe.m_data);
return *this;
}
String::~ String(void)? ? //?析構
{
delete []m_data ;
}
?
?
轉載于:https://www.cnblogs.com/shuang0109/p/9059583.html
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的C/C++ 面试题记录的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 《thor过滤器 thor过滤规则合集资
- 下一篇: 学习笔记(49):Python实战编程-