日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

C++后端面试题目

發(fā)布時間:2023/12/14 c/c++ 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C++后端面试题目 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

C++后端面試知識

    • 1. 師兄建議
    • 2. 內(nèi)存泄漏
      • 怎么避免
      • 怎么檢測
      • 內(nèi)存溢出
    • 3. 堆和棧
    • 4. static
    • 5. const
    • 6. URL
    • 7. C和C++區(qū)別
    • 8. malloc和new區(qū)別
    • 9. 指針和引用區(qū)別
    • 10.C++中內(nèi)存分區(qū)
    • 11. 野指針
    • 12. 類的默認函數(shù)
    • 13. class和struct區(qū)別
    • 14. 構(gòu)造函數(shù)中初始值列表的必要性
    • 15. 虛函數(shù)
    • 16. 繼承中的訪問權(quán)限
    • 17. C++防止頭文件重復包含
    • 18.TCP連接和斷開
    • 19. 長連接和短連接
    • 20. 進程和線程區(qū)別
    • 21. 進程通信和線程通信
    • 22. 線程池
    • 23. 實踐中優(yōu)化MySQL
    • 24. 設計高并發(fā)的系統(tǒng)
    • 25. 小端和大端機器
    • 26. strlen和sizeof區(qū)別

本文多數(shù)總結(jié)來自于CSDN博主「Tracker-for-1995」的文章【C++后端面試知識精選系列】,鏈接為:https://me.csdn.net/trackxiaoxin321。若有錯誤,望指正,筆者的郵箱為:wuxiaofang555555@163.com 。

1. 師兄建議

  • 國企看重簡歷中的硬性指標,如:論文情況、比賽、專利、軟著等
  • Qt
  • C++基礎知識(較瑣碎)
    • 面向?qū)ο缶幊痰奶攸c:抽象、封裝、繼承、多態(tài)
    • 引用的用法
    • 指針的用法
    • 內(nèi)存泄漏
    • 內(nèi)存溢出

2. 內(nèi)存泄漏

指程序中己動態(tài)分配的堆內(nèi)存由于某種原因程序未釋放或無法釋放,造成系統(tǒng)內(nèi)存的浪費,導致程序運行速度減慢甚至系統(tǒng)崩潰等嚴重后果。

當程序員使用new或是malloc分配內(nèi)存,而忘記使用delete或是free釋放內(nèi)存時,容易造成內(nèi)存泄漏。

怎么避免

  • 使用智能指針,而不是手動地去管理內(nèi)存
  • 程序進程字符串處理時,避免使用string代替char*
  • 使用RAII(Resource Acquisition Is Initialization,資源獲取就是初始化),RAII 的做法是使用一個對象,在其構(gòu)造時獲取資源,最后在對象析構(gòu)的時候釋放資源。即把資源用類進行封裝起來,對資源操作都封裝在類的內(nèi)部,在析構(gòu)函數(shù)中進行釋放資源。
  • 盡可能少的使用new,若一定要使用,new/malloc分配內(nèi)存,要及時delete/free釋放

怎么檢測

  • new和delete都是內(nèi)置的操作符

    void * operator new(size_t size); //new 操作符的聲明 //返回一個未初始化的地址,其中size來確定分配多少內(nèi)存
  • 自定義跟蹤new和delete的類

    • 重載new和delete操作符,通過計數(shù)new的次數(shù)和delete次數(shù),即可判斷是否存在內(nèi)存泄漏

    • track_new.h

      #ifndef TRACK_NEW_H #define TRACK_NEW_H #include <map> void* operator new(size_t size, const char *file, long line); void* operator new(size_t size); void operator delete(void *p); class TrackerNew {class TrackerNewIn {const char *m_file;long m_line;public:TrackerNewIn(const char *file = nullptr, long line = 0) :m_file(file), m_line(line){ }~TrackerNewIn(){ }const char *file() const { return m_file; }long line() const { return m_line; }};class Lock { //省去m_lock_cout的自減,避免出錯TrackerNew &_track;public:Lock(TrackerNew &track) :_track(track) {_track.m_lock_count++;}~Lock() {_track.m_lock_count--;}}; public:TrackerNew();~TrackerNew();void add(void *p, const char *file, long line);void remove(void *p);void dump(); public:static bool flag; private:std::map<void*, TrackerNewIn> m_track;long m_lock_count; //為了避免無限調(diào)用 }; extern TrackerNew tracker_new; #endif TRACK_NEW_H //!TRACK_NEW_H
    • track_new.cpp

      #include"track_new.h" #include <cstdlib> #include <iostream> TrackerNew tracker_new;//定義全局的類 bool TrackerNew::flag = false; void* operator new(size_t size, const char *file, long line) {void *p = malloc(size);if (TrackerNew::flag)tracker_new.add(p, file, line);return p; } void* operator new(size_t size) {void *p = malloc(size);if (TrackerNew::flag)tracker_new.add(p, "unknow", -1);return p; } void operator delete(void *p) {if (TrackerNew::flag)tracker_new.remove(p);free(p); } TrackerNew::TrackerNew() :m_lock_count(0) {TrackerNew::flag = true; } TrackerNew::~TrackerNew() {TrackerNew::flag = false;dump(); } void TrackerNew::add(void *p, const char *file, long line) {if (m_lock_count > 0) return;Lock lock(*this);m_track[p] = TrackerNewIn(file, line);/*m_lock_count++;m_track[p] = TrackerNewIn(file, line);m_lock_count--;*/ } void TrackerNew::remove(void *p) {if (m_lock_count > 0)return;Lock lock(*this);auto it = m_track.find(p);if (it != m_track.end()) {m_track.erase(it);} } void TrackerNew::dump() {for (auto it : m_track) {std::cout << "ox: " << it.first << "\t" << "file: " << it.second.file() << "\t" << "line: " << it.second.line() << std::endl;} }
    • main.cpp

      #include "track_new.h" #include "debug_new.h" int main() {int *p1 = new int;delete p1;int *p2 = new int[10];//delete[] p2; return 0; }

內(nèi)存溢出

  • 指應用系統(tǒng)中存在無法回收的內(nèi)存或使用的內(nèi)存過多,最終使得程序運行要用到的內(nèi)存大于能提供的最大內(nèi)存

  • 主要發(fā)生在棧內(nèi)存溢出

  • 遞歸調(diào)用中,若調(diào)用次數(shù)過多,易導致棧溢出

3. 堆和棧

  • 數(shù)據(jù)結(jié)構(gòu)層面

    • :后進先出
    • :二叉堆,樹型結(jié)構(gòu)、可任意訪問
  • 內(nèi)存分配層面(以地址的增長方向為上)

    • 棧區(qū):處于相對較高地址,棧地址是向下增長的;棧中分配局部變量空間
    • 堆區(qū):堆區(qū)是向上增長的用于分配程序員申請的內(nèi)存空間,例如使用malloc、new申請的區(qū)域。

  • 區(qū)別總結(jié)一

    • 堆和棧申請方式不同

      • 棧是系統(tǒng)自動分配空間,如定義一個char a;系統(tǒng)會自動在棧上為其開辟空間。棧上的數(shù)據(jù)的生存周期只是在函數(shù)的運行過程中,運行后就釋放掉了,不能再訪問了。
      • 堆則是程序員根據(jù)需要自己申請的空間,如malloc(10);開辟十個字節(jié)的空間。堆上的數(shù)據(jù)只要程序員不釋放空間,就一直可以訪問,一旦頑疾釋放會造成內(nèi)存泄漏。
  • 申請后系統(tǒng)的響應

    • 棧:只要棧的剩余空間大于所申請空間,系統(tǒng)將為程序提供內(nèi)存,否則將報異常提示棧溢出。

      • 堆:首先應該知道操作系統(tǒng)有一個記錄空閑內(nèi)存地址的鏈表,當系統(tǒng)收到程序的申請時,會遍歷該鏈表,尋找第一個空間大于所申請空間的堆。結(jié)點,然后將該結(jié)點從空閑結(jié)點鏈表中刪除,并將該結(jié)點的空間分配給程序,另外,對于大多數(shù)系統(tǒng),會在這塊內(nèi)存空間中的首地址處記錄本次分配的大小,這樣,代碼中的delete語句才能正確的釋放本內(nèi)存空間。另外,由于找到的堆結(jié)點的大小不一定正好等于申請的大小,系統(tǒng)會自動的將多余的那部分重新放入空閑鏈表中。也就是說堆會在申請后還要做一些后續(xù)的工作這就會引出申請效率的問題
    • 申請效率的比較

      • 由系統(tǒng)自動分配,速度較快。但程序員是無法控制的。
    • 是由new分配的內(nèi)存,一般速度比較慢,而且容易產(chǎn)生內(nèi)存碎片,不過用起來最方便

    • 申請大小的限制

    • 棧是向低地址擴展的數(shù)據(jù)結(jié)構(gòu),是一塊連續(xù)的內(nèi)存的區(qū)域。意思是棧頂?shù)牡刂泛蜅5淖畲笕萘渴窍到y(tǒng)預先規(guī)定好的。因此,能從棧獲得的空間較小。

      • 堆是向高地址擴展的數(shù)據(jù)結(jié)構(gòu),是不連續(xù)的內(nèi)存區(qū)域。堆獲得的空間比較靈活,也比較大。
  • 堆和棧中的存儲內(nèi)容

    • 棧: 在函數(shù)調(diào)用時,第一個進棧的是主函數(shù)中函數(shù)調(diào)用后的下一條指令(函數(shù)調(diào)用語句的下一條可執(zhí)行語句)的地址,然后是函數(shù)的各個參數(shù),在大多數(shù)的C編譯器中,參數(shù)是由右往左入棧的,然后是函數(shù)中的局部變量。注意靜態(tài)變量是不入棧的。當本次函數(shù)調(diào)用結(jié)束后,局部變量先出棧,然后是參數(shù),最后棧頂指針指向最開始存的地址,也就是主函數(shù)中的下一條指令,程序由該點繼續(xù)運行。
    • 堆:一般是在堆的頭部用一個字節(jié)存放堆的大小。堆中的具體內(nèi)容有程序員安排。
    • 存取效率的比較:存取中,棧上的數(shù)據(jù)比堆上的數(shù)據(jù)快。
  • 區(qū)別總結(jié)二

    • 存儲內(nèi)容:棧存放的是局部變量和函數(shù)參數(shù)等;堆存放的是new/malloc申請的變量;
    • 管理方式:棧由系統(tǒng)自動分配,自動釋放;堆由程序員手動申請,手動釋放;
    • 空間大小:32位系統(tǒng)一般堆能達到4G,可以看做堆沒有什么限制的,但棧一般是有特定大小的,windows下一般2M;
    • 生長方向:棧是向下(高地址——>低地址)生長的,堆是向上生長(低地址——>高地址)的;
    • 申請效率:棧由系統(tǒng)自動申請分配,速度較快;堆由new/malloc分配,速度較慢。

4. static

  • 修飾全局變量
    • 修飾全局變量,不初始化默認初始為0,存儲在靜態(tài)存儲區(qū),從聲明到程序結(jié)束一直存在
  • 修飾局部變量
    • 也存儲在靜態(tài)存儲區(qū),作用域是局部作用域,當定義他的函數(shù)或者語句塊結(jié)束時,作用域結(jié)束,但該變量并沒有被銷毀,只不過我們不能訪問,直到該函數(shù)再次被調(diào)用
  • 修飾類的數(shù)據(jù)成員
    • 不屬于類的對象,類內(nèi)聲明,類外初始化,類的靜態(tài)成員變量被所有對象共享,保證了共享性,又具備安全性
  • 修飾類的成員函數(shù)
    • 靜態(tài)成員函數(shù)只能訪問靜態(tài)成員變量不能訪問非靜態(tài)成員函數(shù),原因是靜態(tài)成員函數(shù)不與任何對象綁定,因此不包含this指針,在靜態(tài)成員函數(shù)內(nèi)部不能直接使用this指針,因此不能訪問類的非靜態(tài)成員變量
  • 修飾函數(shù)
    • 靜態(tài)函數(shù),僅在聲明它的cpp文件中使用,其他文件不可使用
  • 面試例子
    • static關(guān)鍵字的作用,修飾函數(shù)有什么用?
      • static修飾的函數(shù)叫靜態(tài)函數(shù),包括兩種
        • 靜態(tài)函數(shù)出現(xiàn)在類里,則它是一個靜態(tài)成員函數(shù)。靜態(tài)成員函數(shù)不與任何對象綁定,因此不包含this指針,在靜態(tài)成員函數(shù)內(nèi)部不能直接使用this指針,即不能直接訪問普通成員函數(shù);靜態(tài)成員函數(shù)屬于類本身,在類加載時就會分配內(nèi)存,可以通過類名直接去訪問;雖然靜態(tài)成員函數(shù)不屬于類對象,但是可以通過類對象訪問靜態(tài)成員函數(shù)。
        • 普通的全局的靜態(tài)函數(shù)。限定在本源碼文件中,不能在其他文件調(diào)用(普通函數(shù)的定義和聲明默認情況下都是extern的,即可被其他文件調(diào)用)。故好處在于:1)其他文件中可以定義相同名字的函

5. const

  • 修飾變量,使其不能被修改

  • 修飾函數(shù)參數(shù),表明輸入的參數(shù)在參數(shù)內(nèi)不能被修改

  • 修飾指針

    • 常量指針,指向的內(nèi)容不能被修改,即指向“常量”的指針 , const int *p
    • 指針常量,指針的指向不能改變,即指針類型的常量,int * const p
  • 修飾類的成員函數(shù),表明其是常函數(shù),即不能修改類的成員變量,const成員函數(shù)斌調(diào)用非const成員函數(shù),因為非const成員函數(shù)可能會修改成員變量

    class A {int m_a; public:void get() const { } //函數(shù)體里不能修改成員變量 }

6. URL

  • 瀏覽器輸入www.baidu.com發(fā)生了什么?(百度面試題)
    • 首先瀏覽器向域名系統(tǒng)DNS請求將域名地址轉(zhuǎn)換為IP地址,然后與百度服務器建立TCP連接發(fā)送http請求(默認端口80)請求百度首頁,服務器處理請求并將首頁文件發(fā)給瀏覽器,TCP連接釋放,瀏覽器解析首頁文件展示web界面

7. C和C++區(qū)別

  • C是面向過程的編程語言,C++是面向?qū)ο蟮慕Y(jié)構(gòu)化編程語言,C++是C的擴展,但C和C++確是兩種不同的語言;
  • C++有抽象、封裝、繼承、多態(tài)幾大特性,C+相比于C,增加了許多類型安全的功能,同時還有功能強大STL標準庫;
  • 作用域,C中只有局部和全局C++有局部、類作用域和名稱作用域三種;
  • 開辟/釋放空間,C用malloc和free(函數(shù)),C++使用new和delete(關(guān)鍵字),new開辟空間在堆區(qū)或者自由存儲區(qū)(C plus plus原話:if the object is created by using new,it resides in heap memory, or the free store and its destructor is called automatically when you use delete to free the memory),malloc開辟在堆區(qū)
  • C++有引用,C中沒有;
  • const不同,C中的const叫只讀變量,只是無法做左值的變量;C++中的const是真正的常量,但也有可能退化成c語言的常量,默認生成local符號;
  • C++靈活、可擴展、易于維護,耦合性較低,C語言耦合性較高。

8. malloc和new區(qū)別

  • malloc和new都是在堆上開辟內(nèi)存的。malloc只負責開辟內(nèi)存,沒有初始化功能,需要用戶自己初始化;new不但開辟內(nèi)存,還可以進行初始化,如new int(10);表示在堆上開辟了一個4字節(jié)的int整形內(nèi)存,初始值是10,再如new int[10] ();表示在堆上開辟了一個包含10個整形元素的數(shù)組,初始值都為0。

  • malloc是函數(shù),開辟內(nèi)存需要傳入開辟空間的大小(字節(jié)數(shù)),返回類型為void*,表示分配的堆內(nèi)存的起始地址,因此malloc的返回值需要轉(zhuǎn)換成指定類型的地址new是運算符,開辟內(nèi)存需要指定類型,返回指定類型的地址,因此不需要類型轉(zhuǎn)換

    int *p1 = (int*)malloc(sizeof(int)); //根據(jù)傳入字節(jié)數(shù)開辟內(nèi)存,沒有初始化 int *p2 = new int(0); //根據(jù)指定類型int開辟一個整形內(nèi)存,初始化為0int *p3 = (int*)malloc(sizeof(int)*100); //開辟400個字節(jié)的內(nèi)存,相當于包含100個整形元素的數(shù)組,沒有初始化 int *p4 = new int[100](); //開辟400個字節(jié)的內(nèi)存,100個元素的整形數(shù)組,元素都初始化為0
  • malloc開辟內(nèi)存失敗返回nullptr(空指針),new開辟內(nèi)存失敗拋出bad_alloc類型的異常,需要捕獲異常才能判斷內(nèi)存開辟成功或失敗,new運算符其實是operator new函數(shù)的調(diào)用,它底層實現(xiàn)也是調(diào)用的malloc函數(shù),new它比malloc多的就是初始化功能,對于類類型來說,所謂初始化,就是調(diào)用相應的構(gòu)造函數(shù)。

  • malloc開辟的內(nèi)存是通過free來釋放的;而new單個元素內(nèi)存,用的是delete,如果new[]數(shù)組,用的是**delete[]**來釋放內(nèi)存的。

  • malloc開辟內(nèi)存只有一種方式,而new有四種分別是普通的new(內(nèi)存開辟失敗拋出bad_alloc異常), nothrow版本的new,const new以及定位new。

  • new/delete會調(diào)用對象的構(gòu)造函數(shù)/析構(gòu)函數(shù)以完成對象的構(gòu)造/析構(gòu),而malloc不會

  • new/delete可以被重載,但malloc/free不能

  • new/delete 和 new[]/delete[] 在自定義的類類型對象有析構(gòu)函數(shù)時,不能混用

9. 指針和引用區(qū)別

  • 指針本質(zhì)是地址,有自己的一塊空間,引用本質(zhì)是某一個變量的別名
  • 指針初始化可以為空引用初始化必須有確定的對象(取別名的本體要存在,否則不存在別名一說);
  • 指針大小為指針本身的大小,為4字節(jié)(32位機器為4,64位機器為8),引用的大小是變量的大小
  • 指針可以改變指向,但引用不行(一旦為A的別名,不能再成為B的別名);
  • 引用比指針安全(指針可能存在野指針的情況);

10.C++中內(nèi)存分區(qū)

  • 五大分區(qū):棧、自由存儲區(qū)、堆、全局/靜態(tài)存儲區(qū)、常量存儲區(qū)

  • 棧區(qū):編譯器自行開辟自行釋放的內(nèi)存區(qū),一半存放局部變量和函數(shù)參數(shù)等。

  • 自由存儲區(qū):一般是malloc開辟的空間,與堆區(qū)類似,但不等價于堆區(qū),幾乎所有的編譯器都用堆來實現(xiàn)自由存儲(堆是操作系統(tǒng)維護的一塊內(nèi)存,而自由存儲是C++通過new/delete實現(xiàn)動態(tài)內(nèi)存分配和釋放對象的抽象概念)。

  • 堆區(qū):由程序員手動開辟手動釋放,一般是new開辟的空間(new開辟的也可能在自由存儲區(qū)),如果程序員不釋放,OS可能回收,但也可能造成內(nèi)存泄露。

  • 全局/靜態(tài)存儲區(qū):存放全局變量,靜態(tài)變量(static關(guān)鍵字修飾的),一般是被共享的。

  • 常量存儲區(qū):保存常量,這部分的數(shù)據(jù)不允許被修改。

11. 野指針

  • 野指針是指向不可用內(nèi)存的指針(并不是指向nullptr,不能用if判斷一個指針是否是野指針,良好的編程習慣是杜絕野指針的唯一方法)。

  • 野指針形成原因

    • 指針變量沒有被初始化。任何指針變量剛被創(chuàng)建時不會自動生成nullptr指針,它的指向是隨機的,在創(chuàng)建指針時應當被初始化,要么將指針指向nullptr,要么讓它指向合法的地址。

    • 指針被free和delete(只是將內(nèi)存釋放,并沒有把指針干掉)后沒有置為nullptr

    • 指針操作超出了變量的作用范圍,比如某個函數(shù)結(jié)束后,其局部變量會銷毀,此時如果指針指向該變量,在其他地方是不能使用的。

      int *p; {int a;p=&a;cout<<*p<<endl; } cout<<*p<<endl; //此時p成為野指針,因為其所指向的局部變量a過了生命期

12. 類的默認函數(shù)

一個空類會生成以下默認函數(shù):默認構(gòu)造函數(shù)、默認析構(gòu)函數(shù)、默認拷貝構(gòu)造函數(shù)、默認拷貝賦值函數(shù)

13. class和struct區(qū)別

  • class默認繼承訪問權(quán)限為private繼承,而struct是public繼承

  • class默認訪問屬性是private,而struct是public

  • class具有繼承、多態(tài)等性質(zhì),而struct不具備

  • class能夠定義模板函數(shù),而struct不行

14. 構(gòu)造函數(shù)中初始值列表的必要性

在執(zhí)行構(gòu)造函數(shù)時,當執(zhí)行到函數(shù)體內(nèi)部時,所有的數(shù)據(jù)成員就已經(jīng)在內(nèi)存中創(chuàng)建,并利用類內(nèi)默認值初始化(如果類內(nèi)提供了初始值)。

對于引用類型的成員或是有const修飾符的成員,必須要利用初始值列表進行初始化,否則將會錯過初始化的時機,無法完成初始化。

  • 必須在初始值列表中定義的數(shù)據(jù)成員
    • 引用類型的成員
    • 有const修飾符的成員
    • 沒有默認構(gòu)造函數(shù)的類類型

15. 虛函數(shù)

  • 虛函數(shù)是C++實現(xiàn)多態(tài)的重要保障,當類中有虛函數(shù)時,就存在一個虛函數(shù)指針指向虛函數(shù)表,虛函數(shù)表存放著虛函數(shù)的地址

  • 派生類繼承基類時,虛函數(shù)指針虛函數(shù)表都繼承了,當派生類重寫基類的虛函數(shù)后,派生類的虛函數(shù)表存的地址就變成了派生類重寫的虛函數(shù)地址

  • 當基類指針或引用指向派生類時,就產(chǎn)生了多態(tài)

  • 含有純虛函數(shù),則為抽象類,不能被實例化

    virtual void get() = 0; //純虛函數(shù)

16. 繼承中的訪問權(quán)限

  • 派生類繼承基類

    class Student :public Person{ //若省略public,則默認為private繼承... }
  • 若派生類public繼承基類,派生類能否訪問基類中的成員,取決于其在基類中的訪問限定聲明;若為private,則派生類不能訪問;一般我們采用protected來修飾基類中的成員,以實現(xiàn)在派生類中的訪問權(quán)限

    class Base { private:int m_pri; //private 成員, 在基類以外的地方,均不能被訪問 protected:int m_pro; //protected 成員, 在派生類中可被訪問,在其他地方不能被訪問 public:int m_pub; //public 成員, 在類內(nèi)類外均可被訪問 }; class PubDerv :public Base {void foo() {m_pri = 10;//錯誤:不能訪問 Base 類私有成員m_pro = 1; //正確:可以訪問 Base 類受保護成員} }; void test() {Base b;b.m_pro = 10;//錯誤:不能訪問 Base 受保護成員 }
  • protected修飾符可以看作是private和public的混合物

    • 和公有成員類似,基類中受保護(protected)的成員在其派生類里是可以訪問的
    • 和私有成員類似,基類中受保護的成員在類外是無法訪問的

17. C++防止頭文件重復包含

兩種方式防止頭文件重復包含

  • ifndef語句,如下為myHeader.h

    #ifndef MYHEADER_H #define MYHEADER_H // 頭文件主題 #endif // !MYHEADER_H
  • #pragma once語句

    #pragma once // 頭文件主題

由于第二種是windows下的,建議使用第一種

18.TCP連接和斷開

  • 三次握手

  • 四次揮手

19. 長連接和短連接

長連接和短連接指的是TCP的長連接和TCP的短連接。

  • TCP長連接:TCP長連接指建立連接后保持連續(xù)而不斷,如一段時間沒有數(shù)據(jù)交互,保活定時器超時后,服務端會發(fā)送探測報文給客戶端檢測客戶端是否在線。連接—傳輸數(shù)據(jù)—保活—傳輸數(shù)據(jù)—保活—…。
  • TCP短連接:指建立并傳輸數(shù)據(jù)完成后立即斷開。連接—傳輸數(shù)據(jù)—斷開
  • 應用場景長連接適用單對單通信連接數(shù)不太多的情況,短連接適用于連接數(shù)多經(jīng)常需要更換連接對象的情況。
  • 說明:HTTP/1.0中,默認使用短連接,HTTP/1.1起,默認使用長連接。HTTP的長連接也不是永久保持連接,保活計時器超時后,探測報文沒回應,那么也會斷開連接。

20. 進程和線程區(qū)別

  • 進程是操作系統(tǒng)進行資源分配和調(diào)度的基本單位,而線程是操作系統(tǒng)進行運行調(diào)度的最小單位,包含在進程中,是進程中實際工作的單位;
  • 線程存在于進程之中,與進程是多對一的關(guān)系,一個進程可以存在多個線程這些線程共享進程資源
  • 進程有自己的獨立地址空間,每啟動一個進程,系統(tǒng)就會為他分配地址空間,建立數(shù)據(jù)表來維護代碼段、堆棧段和數(shù)據(jù)段,這種操作非常昂貴;線程共享進程的空間及數(shù)據(jù)
  • 線程之間的通信更方便(共享全局變量、靜態(tài)變量等數(shù)據(jù)),而進程通信需要以通信方式(管道、消息隊列、信號量、共享存儲、socket、streams)進行。
  • 多進程程序更健壯多線程程序只有有一個線程死掉,整個進程也死掉了。而一個進程死掉,不影響另外一個進程,因為進程有獨立空間。

21. 進程通信和線程通信

  • 進程間通信方式(InterProcess Communication, IPC)
    • (無名)管道(pipe):是一種半雙工的通信方式,數(shù)據(jù)只能單向流動,而且只能在具有親緣關(guān)系的進程間使用。進程的親緣關(guān)系通常是指父子進程關(guān)系。
    • 命名管道(namedpipe):可以在無關(guān)進程之間交換數(shù)據(jù)。
    • 消息隊列(messagequeue):是消息的鏈接表,存放在內(nèi)核中,一個消息隊列由一個標識符(隊列ID)來標識。消息隊列是面向記錄的,其中的消息具有特定的格式以及特定的優(yōu)先級;獨立于發(fā)送與接收進程,進程終止時,消息隊列及其內(nèi)容不會被刪除;可以實現(xiàn)消息的隨機查詢。
    • 信號量(semophore):它是一個計數(shù)器,用于實現(xiàn)進程間的互斥與同步,而不是用于存儲進程間通信數(shù)據(jù)。用于進程間同步,若要在進程間傳遞數(shù)據(jù)需要結(jié)合共享內(nèi)存。
    • 共享內(nèi)存(shared memory):指兩個或多個進程共享一個給定的存儲區(qū)。共享內(nèi)存是最快的IPC,因為進程是直接對內(nèi)存進行存取;因為多個進程可以同時操作,所以需要同步;信號量+共享內(nèi)存通常結(jié)合在一起使用,信號量用來同步對共享內(nèi)存的訪問。
    • 套接字(socket):是一種進程間通信機制,與其他通信機制不同的是,它可用于不同設備及其間的進程通信
    • 總結(jié)
      • 管道:速度慢,容量有限,只有父子進程能通訊
      • 命名管道:任何進程間都能通訊,但速度慢
      • 消息隊列:容量受到系統(tǒng)限制,且要注意第一次讀的時候,要考慮上一次沒有讀完數(shù)據(jù)的問題
      • 信號量:不能傳遞復雜消息,只能用來同步
      • 共享內(nèi)存:能夠很容易控制容量,速度快,但要保持同步,比如一個進程在寫的時候,另一個進程要注意讀寫的問題,相當于線程中的線程安全
  • 線程間通信方式
    • 鎖機制:互斥鎖、條件變量、讀寫鎖
    • 信號量機制:無名線程信號量和命名線程信號量

22. 線程池

由于線程的創(chuàng)建和銷毀需要消耗資源,當線程頻繁創(chuàng)建和銷毀時或者線程創(chuàng)建和銷毀的時間大于線程執(zhí)行的時間,那么單純的采用線程創(chuàng)建/銷毀策略明顯不合適,所以有了線程池的概念,線程池中存放一定數(shù)量創(chuàng)建好的線程,需要用的時候拿出來用,用完之后再放到池子里。

  • 線程池的好處就是

    • 降低了頻繁創(chuàng)建銷毀線程的開銷
    • 提高了響應速度
    • 提高了線程的可管理性;
  • 線程池組成部分

    • 線程管理池:用于創(chuàng)建和管理線程池,有創(chuàng)建、銷毀、添加新任務
    • 工作線程:線程池中的線程,其在沒有任務的時候處于等待狀態(tài),可以循環(huán)的執(zhí)行任務
    • 任務隊列:用于存放沒有處理的任務,提供一種緩存機制
    • 任務接口:每個任務必須實現(xiàn)接口,以供工作線程調(diào)度任務的執(zhí)行,規(guī)定了任務的入口及執(zhí)行結(jié)束的收尾工作和任務的執(zhí)行狀態(tài)等
  • 線程池工作流程

    • 判斷順序:核心線程池、隊列、線程池

23. 實踐中優(yōu)化MySQL

  • SQL語句及索引的優(yōu)化;
  • 數(shù)據(jù)表結(jié)構(gòu)的優(yōu)化;
  • 系統(tǒng)配置的優(yōu)化;
  • 硬件的優(yōu)化。

上述四條從效果上來說,第一條影響最大,后面越來越小。

24. 設計高并發(fā)的系統(tǒng)

  • 數(shù)據(jù)庫的優(yōu)化,包括合理的事務隔離級別、SQL語句優(yōu)化、索引優(yōu)化
  • 使用緩存,盡量減少數(shù)據(jù)庫IO操作;
  • 分布式數(shù)據(jù)庫、分布式緩存;
  • 服務器的負載均衡。

25. 小端和大端機器

  • 小端/大端的區(qū)別是指低位數(shù)據(jù)存儲在內(nèi)存低位還是內(nèi)存高位
  • 小端機器數(shù)據(jù)低位存儲在內(nèi)存低位數(shù)據(jù)高位則存儲在內(nèi)存高位
  • 大端機器數(shù)據(jù)低位存儲在內(nèi)存高位數(shù)據(jù)高位存儲在內(nèi)存低位
  • 目前絕大多數(shù)都是小端機器,符合人們的邏輯思維的數(shù)據(jù)存儲方式。

26. strlen和sizeof區(qū)別

  • strlen就算字符串長度
  • sizeof會將結(jié)束符算進去
strlen("12345678");//8 sizeof("12345678");//9 char str1[] = { 'a','b', 'c', 'd', 'e', '\0', 'a', 'b' }; int s1 = strlen(str1); //5 int s1_ = sizeof(str1); //8char str2[] = "abcde"; int s2 = strlen(str2); //5 int s2_ = sizeof(str2); //6char *str3 = "abcde"; int s3 = strlen(str3); //5 int s3_ = sizeof(str3); //4int str4[10] = "abc"; int s4 = strlen(str4); //3 int s4_ = sizeof(str4); //10

總結(jié)

以上是生活随笔為你收集整理的C++后端面试题目的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。