【C++软件开发】面试经典题目汇总
一:C++中指針和引用的區別
1.指針是用來保存存儲地址的,一般需要初始化NULL。
引用是取別名(類似小名),定義的時候一定要初始化,不能為NULL。
2.引用不占用字節,但引用不可以改變:引用和變量指向同一片內存。
指針占用4個字節,指針可以指向不同的地址,可以改名稱。
3.引用比指針使用起來會更加簡潔,安全。使用指針時要特別注意野指針。
4.在sizeof中含義不同:引用結果為引用類型的大小,指針始終是地址空間所占字節個數(32位:4字節 64位8字節)。
5.引用自加即引用的實體增加1,指針自加即指針向后偏移一個數據類型的大小。
6.有多級指針,但是沒有多級引用。
7.訪問實體方式不同,指針需要顯式解引用,引用則是編譯器自己處理。
二:C++中重寫和重載的區別
1.重載(overload):函數名相同,函數的參數個數,參數類型或者參數順序三者中必須至少有一種不同。函數返回值的類型可以相同,也可以不同。發生在一個類內部,不能跨作用域。也就是說使用同一個函數去完成不同的功能。
2.重寫(override):也叫做覆蓋,一般發生在子類和父類繼承關系之間。子類重新定義父類中有相同名稱和參數的虛函數,返回值可以不相同,但是必須是父子關系的指針或者引用。
重寫需要注意:
a.被重寫的函數不能是static,必須是virtual
b.重寫函數必須有相同的類型,名稱和參數列表
c.重寫函數的訪問修飾符(public/private/protected)可以不同
三:什么是進程
程序的執行實例被稱為進程(process)。簡單來說,進程是動態的概念,指的是程序的一次運行活動,通俗點來看就是程序運行起來了的時候,系統中就多了一個進程。進程相當于是程序的一次執行過程。進程包含線程。
四:什么是程序
程序(program)是存放在磁盤文件中的可執行文件。是靜態的。
五:程序和進程的區別
1.程序是指令和數據的有序集合,是一個靜態的概念,而進程是程序在處理機上的一個執行過程,它是一個動態的概念。
2.程序可以作為一種軟件資料長期存在,而進程是有一定生命周期的。程序是永久的,進程只是暫時的。
3.進程是進程控制塊,程序段,數據段三部分組成。
4.進程具有創建其他進程的功能,而程序沒有。
5.同一程序同時運行于若干個數據集合上,它將屬于若干個不同的進程,也就是說同一個程序可以對應多個進程。
6.在傳統的操作系統中,程序并不能獨立運行,作為資源分配和獨立運行的基本單元都是進程。
六:為什么要使用進程
如果程序在運行的過程中,頻繁地請求IO操作,那么CPU就會等待該程序的IO操作完成后再為其服務,這就大大的浪費了CPU資源,降低CPU效率。因此采用一種“程序排隊”機制來提高CPU利用效率,從而產生了進程。
七:深拷貝和淺拷貝 區別 以及 使用場景
1.拷貝構造函數:是一種特殊的構造函數,由編譯器調用來完成一些基于同一類的其他對象的構件以及初始化。
2.使用場景
a.函數參數中以值傳遞的方式傳入時,會將傳入的實際參數拷貝一份。
b.函數返回中返回了一個局部對象,會將其拷貝一份并且返回。
c.在給一個對象初始化的時候(不是賦值),會將值拷貝一份。
3.什么是深拷貝和淺拷貝
淺拷貝:只是對指針的拷貝,拷貝后兩個指針指向同一個內存空間。
深拷貝:不但對指針進行拷貝,而且對指針指向的內容進行拷貝,經過深拷貝后的指針是指向兩個不同地址的指針,也就是程序員自己編寫的拷貝構造函數。
重點:系統默認生成的拷貝構造函數是淺拷貝,深拷貝是程序員自己編寫的拷貝構造函數。
4.淺拷貝造成的問題
a.淺拷貝只是拷貝了指針,使兩個對象的指針指向同一地址,在對象結束的時候,會造成同一塊內存資源析構兩次,造成程序崩潰。
b.指針指向同一塊內存,任何一方有改動都會影響另一方。
c.在釋放內存時,后者的內存先釋放會導致前者的內存也釋放,導致空間不能再被利用、
以上的這些問題就可以使用到深拷貝來進行避免!
八:C中的new和malloc的區別
molloc開辟一塊內存,不進行初始化(動態開辟內存)
new用來開辟內存,需要進行初始化(動態內存管理)
區別
1.malloc以及free都是函數(C語言),而new delete都是運算符(C++),都開在堆區。
2.malloc需要指定開辟空間大小,new不需要,知道數據類型即可。
3.malloc返回void*,一般強制轉換。new則不需要。
4.malloc開free收,new開delete釋放。
5.new內存分配失敗時,會拋出異常警告。malloc分配內存失敗時會返回NULL。
6.new不僅能開辟內存,還能進行初始化,malloc只能開辟內存,不能初始化。
7.new開辟的內存叫做自由存儲區,malloc開辟的內存叫做堆區。
8.new可以重載,malloc不能重載。
9.new開辟數組時,用[ ]傳入數組的大小。
10.new在創建類的時候,會默認調用構造函數,而malloc不會。
11.delate會默認調用類的析構函數,而free不會。
12.如果父類的析構函數有寫虛函數的關鍵字,當子類被析構的時候,會默認調用父類的析構函數。
九:簡述通用鏈表的原理
通用鏈表是一個鏈式結構,其中至少包含一個指針域和一個數據域。如果只包含一個,就表示指針域時指向下一個節點。如果是雙向鏈表,其中包含一個數據域和兩個指針域。一個指針域指向上一個節點,一個指針域指向下一個節點。通常情況下,鏈表的添加是尾部添加,當然也有中間插入的,主要是看是什么容器。刪除節點:list容器可以從中間刪除和尾部刪除。隊列只可以頭部刪除,尾部追加,不存在數據插入。
十:模板類和類模板 區別和作用
模板類是類,類模板是模板。
類模板需要我們自己去寫(將邏輯什么的寫好放入),而模板類是將寫好的類模板將參數傳遞進去。容器本來就是一個模板類。它的底層原理就是模板類。
十一:為什么需要使用自定義通信協議
所謂通訊協議就是指 通信雙方對數據傳送控制的一種約定。約定中包括有對數據格式,同步方式,傳送速度,傳送步驟,糾錯方式以及控制字符定義等問題做出統一規定,通信雙方必須同時遵守,倘若一方不遵守,就會直接導致數據不能被解析!
更通俗來講,它可以理解為兩個節點之間為了協同工作實現信息交換,協商一定的規則和約定,例如規定字節序,各個字段類型等。我們最常見的可能就是TCP(傳輸控制協議)/IP(網絡協議)、UDP(用戶數據報協議)等。
不過,上面提到的這些協議是操作系統已經設定好的,并且廣泛應用在網絡通信中。最重要的一點是我們不能更改這些協議。而用戶自定義的通訊協議就不同了。它的實現需要用戶自己設定數據發送的格式以及數據的封裝形式。然后通過上面的網絡傳輸協議發送給對端,對端再根據自己定義好的協議對數據進行解析,從而得到想要的數據。
自定義通信協議組成:協議頭 + 協議體 (定長包頭 + 不定長包體)
協議頭里包含:服務器是什么業務
協議體里包含:具體業務數據參數
十二:進程和線程的區別
進程(Process)是計算機中的程序關于某數據集合上的一次運行活動,是系統進行資源分配和調度的基本單位,是操作系統結構的基礎。
線程是“一個進程內部的控制序列”。
根本區別:進程是操作系統資源分配的基本單位,而線程是處理器任務調度和執行的基本單位。
資源開銷:每個進程都有獨立的代碼和數據空間(程序上下文),程序之間的切換會有較大的開銷。線程可以看作是輕量級的進程,同一類線程共享代碼和數據空間,每個線程都有自己的獨立的運行棧和程序計數器(PC),線程之間切換的開銷小。
包含關系:如果一個進程內有多個線程,則執行過程不是一條線的,而是多條線(線程)共同完成的,線程是進程的一部分,所以線程也被稱為輕權進程或者輕量級進程。
內存分配:同一進程的線程共享本進程的地址空間和資源,而進程之間的地址空間和資源是相互獨立的。
影響關系:一個進程崩潰后,在保護模式下不會對其他的進程產生影響,但是一個線程崩了就會導致整個進程卡死,所以多進程要比多線程更健壯。
執行過程:每個獨立的進程有程序運行的入口,順序執行序列和程序出口,但是線程不能獨立運行,必須依存在應用程序中,由應用程序提供多個線程執行控制,兩者均可以并發執行。
十三:TCP和UDP的區別
TCP和UP都是傳輸層協議
1.TCP面向連接(如打電話要先撥號建立連接),UDP是無連接的,即發送數據之前不需要建立連接。
2.TCP提供可靠的服務,也就是說,通過TCP連接傳送的數據,無差別,不丟失,不重復,并且按序到達,UDP盡最大的努力去交付,即不保證可靠交付。
TCP通過校驗和,重傳控制,序號標識,滑動窗口,確認應答實現可靠傳輸,如丟包時的重發控制,還可以對次序亂掉的分包進行順序控制。
3.UDP具有較好的實時性,工作效率比TCP高,適用于對高速傳輸和實時性有較高的通信或廣播通信。
4.每一條TCP連接只能是點到點的,UDP支持一對一,一對多,多對一,和多對多的交互通信。
5.TCP對系統資源要求較多,UDP對系統資源要求較少。
十四:通信協議的作用
通信協議又稱為通信規程,是指通信雙方對數據傳送控制的一種約定。約定中包括對數據格式,同步方式,傳送速度,傳送步驟,檢糾錯方式以及控制字符定義等問題做出統一規定,通信雙方必須共同遵守,它也叫做鏈路控制規程。
電腦和電腦之間的溝通必須講述相同的語言,才能互相傳輸信息,自然資料在國際互聯網上傳遞,每一份都要符合一定的規格(即是相同的語言)。
這些規格(語言)的規定都是事先在會議上講好的,一般我們稱之為“協議”(英文稱為protocol),而這種在網絡上負責定義資料傳輸規格的協議,我們就統稱為通信協議。
十五:拷貝構造函數 為什么使用const&
調用拷貝構造函數的三種情況
1.用已知的對象拷貝生成新對象
2.以值傳遞的方式傳入函數
3.函數的返回值 是以值傳遞的方式
在值傳遞的時候,傳參期間會產生一個臨時變量,當我們實例化對象d1后,將d1拷貝給d2時調用拷貝構造函數,此時d1發生值傳遞,d1將值傳遞給臨時對象dd1,因為是值傳遞,一旦調用又要產生臨時變量ddd1,將d1的值傳遞給臨時變量ddd1,那么問題就很明顯了,值傳遞,會進行形參實例化,類 類型實例化,會再調用構造函數,就會一直調用,因此結果就是無窮遞歸,所以要使用引用傳參。
第三種參數的返回值是以值傳遞的方式,首先我們需要知道,返回一個局部變量是通過一個臨時的變量返回,對象也不例外,這里也會產生一個臨時的對象,而這個臨時對象,具有常性,也就是const,不可被修改,賦值之后臨時對象也就消亡了。臨時對象,具有const常性。所以當我們把const加上,通過嚴格的參數匹配,編譯器才能找到我們的const&版本的拷貝構造函數。
以下問題需要重點掌握!?
十六:線程池的設計以及作用
線程池的作用:
線程池是為了解決線程在程序中因頻繁創建和銷毀而消耗大量的時間而存在的,即在程序開始正式任務之前,先創建出一些線程,這些線程在程序不會被銷毀,而且程序在運行中也不會再去創建線程。這樣在程序的運行期間就提高了效率。
線程池的設計思路:
先創建出一組線程,當有新任務進來時就從線程池中取出空閑線程處理任務,任務完成之后又會重新放回去,當線程池中的所有線程都在任務時,只能等待有線程結束任務才能繼續執行?。
十七:線程和進程的區別
根本區別:進程是操作系統資源分配的基本單位,而線程是CPU任務調度和執行的基本單位
在開銷方面:每個進程都有獨立的代碼和數據空間(程序上下文),程序之間的切換會有比較大的開銷;線程可以看作是輕量級的進程,同一類線程共享代碼和數據空間,每個線程都有自己獨立的運行棧和程序計數器(PC),線程之間切換的開銷小。
所處環境:在操作系統中同時運行多個進程(程序);而在同一進程(程序)中有多個線程同時執行(通過CPU調度,在每個時間片中只有一個線程執行)
內存分配方面:系統在運行的時候會為每個進程分配不同的內存空間;而對線程而言,除了CPU外,系統不會為線程分配內存(線程所使用的資源來自其所屬進程的資源),線程組之間只能共享資源。
包含關系:一個線程只能屬于一個進程,但是一個進程可以擁有多個線程。多線程處理就是允許一個進程中在同一時刻執行多個任務。所以線程也被稱為輕權進程或者輕量級進程
十八:C++設計模式
單例模式
概念:是指在內存中只會創建且創建一次對象的設計模式
優點:
1.保證一個類只有一個實例,并提供一個訪問它的全局訪問點,使得系統中只有一個唯一的一個對象實例。這樣就防止其他對象對自己的實例化,確保所有的對象都訪問一個實例
2.由于在系統內存中只存在一個對象,因此可以節約系統的資源,提高系統的性能
缺點:
就是不適用于變化的對象,如果同一類型的對象總是要在不同的用例場景發生變化,單例就會引起數據的錯誤,不能保存彼此的狀態
實現要點:
在類中,要構造一個實例,就必須調用類的構造函數,并且為了保證全局只有一個實例,需要防止在外部調用類的構造函數而構造實例,需要將構造函數的訪問權限標記為private,同時阻止拷貝創建對象時賦值拷貝對象,因此也將它們聲明并權限標記為private;另外,需要提供一個全局訪問點,就需要在類中定義一個static函數,返回在類內部唯一構造的實例
觀察者模式:
觀察者模式定義了對象間的一對多依賴關系,讓一個或多個觀察者對象觀察一個主題對象。當主題對象的狀態發生變化時,系統能通知所有的依賴于此對象的觀察者對象,從而使得觀察者對象能夠自動更新
實現方式:
a.角色抽象類(提供對觀察者的添加,刪除和通知功能)
b.角色具體類,實現a,維護一個c的集合(對角色抽象類的實現)
c.觀察者抽象類(被角色通知后實現的方法)
d.觀察者實現類,實現c(多個)
工廠模式
工廠模式包括三種:簡單工廠模式、工廠方法模式、抽象工廠模式
工廠模式的主要作用是封裝對象的創建,分離對象的創建和操作過程,用于批量管理對象的創建過程,便于程序的維護和擴展
簡單工廠是工廠模式最簡單的一種實現,對于不同產品的創建定義一個工廠類,將產品的類型作為參數傳入到工廠的創建函數,根據類型分支選擇不同的產品構造函數
十九:進程間的通訊方式
管道:數據只能單向流動,速度慢,容量有限,只有父子進程能通訊
消息隊列:就是一個消息的鏈表,是一系列保存在內核中消息的列表。用戶進程可以向消息隊列添加消息,也可以向消息隊列讀取消息
共享內存:映射一段能被其他進程訪問的內存,這段內存由一個進程創建,但是多個進程都可以訪問
信號量:是一個計數器,用于控制多個進程間對共享資源的訪問
套接字:用于不同計算機之間的不同進程間通信
二十:引用和指針的區別
本質:引用是別名,指針是地址
相同點:都是地址的概念
指針指向一塊內存,它的內容是所指內存的地址;而引用則是某塊內存的別名
不同點:
1.引用不可以為空,但指針可以為空,故定義一個引用的時候,必須初始化
2.引用不可以改變指向,對一個對象“至死不渝”;但是指針可以改變指向,而指向其他對象,雖然引用不可以改變指向,但是可以改變初始化對象的內容
3.引用的大小是所指的變量的大小,因為引用只是一個別名而已;指針是指針本身的大小,4個字節
4.引用比指針更加安全,由于不存在空引用,并且引用一旦被初始化為指向一個對象,它就不能被改變為另一個對象的引用,因此引用很安全。對于指針來說,它可以隨時指向別的對象,并且可以不被初始化,或為NULL,所以不安全
5.引用僅在聲明時帶有引用運算符“&”,以后像普通變量一樣使用,不能再帶“&”,其他場合使用的"&"都是地址操作符
二十一:構造函數和析構函數
構造函數的作用:用于新建對象的初始化工作(一個類可以有多個構造函數,構造函數可以重載,不可以加虛函數)
析構函數的作用:用于在撤銷對象前,完成一些清理工作,比如:釋放內存等(一個類只能有一個析構函數,不可以重載)
拷貝構造函數:拷貝構造函數是一種特殊的構造函數,函數的名稱必須和類名稱一致,它的唯一的一個參數是本類型的一個引用變量,該參數是const類型,不可變的
二十二:深拷貝和淺拷貝
淺拷貝:淺拷貝是對指針進行拷貝,拷貝后兩個指針指向同一塊內存空間。C++中如果不定義類的賦值構造函數,就會調用類的默認賦值構造函數,而類的賦值構造函數是淺拷貝
深拷貝:深拷貝是對指針進行拷貝而且還對內容進行拷貝,拷貝完成后,指針指向的地址不一樣,但是值是一樣的
淺拷貝和深拷貝的區別:前者就是使用編譯器提供的默認拷貝構造函數或者默認賦值構造函數,后者是自己顯示實現的拷貝/賦值構造函數
二十三:對多態的理解
C++中的虛函數的作用主要是實現了多態的機制。關于多態,簡而言之就是用父類類,別的指針指向其子類的實例,然后通過父類的指針調用實際子類的成員函數
多態的實現主要分為靜態多態和動態多態,靜態多態主要是重載,在編譯的時候就已經確定;動態多態是用虛函數機制實現的,在運行期間動態綁定
多態的條件:
1.必須有繼承
2.要有虛函數重寫
3.用父類指針(引用)指向子類對象
多態的基礎理論:
聯編:一個程序模塊,代碼之間互相關聯的過程
動態聯編:把程序聯編的過程,推遲到運行時進行
靜態聯編
多態的實現效果:
同樣的調用語句,不同的表現形態
多態的意義:設計模式的基礎,編寫框架的基礎,函數指針做函數參數
二十四:數據結構有哪些
什么是數據結構:
數據結構是指相互之間存在著一種或者多種關系的數據元素的集合和該集合中數據元素之間的關系組成
常用的數據結構有:數組、棧、鏈表、隊列、樹、圖、堆、散列表等
數組:數組是可以在內存中連續存儲多個元素的結構,在內存中的分配也是連續的,數組中的元素通過數組下標進行訪問
棧:棧是一種特殊的線性表,僅能在線性表的一端操作,棧頂允許操作,棧底不允許操作。棧的特點是:先進先出,或者說是后進先出
隊列:隊列與棧一樣,也是一種線性表,不同的是,隊列可以在一端添加元素,在另一端取出元素,也就是:先進先出
鏈表:鏈表是物理存儲單元上非連續的,非順序的存儲結構,數據元素的邏輯順序是通過鏈表的指針地址實現,每個元素包含兩個結點,一個是存儲元素的數據域(內存空間),另一個是指向下一個節點地址的指針域。根據指針的指向,鏈表能形成不同的結構,例如單鏈表、雙向鏈表、循環鏈表等
樹:樹是一種數據結構,它是由n(n>=1)個有限節點組成一個具有層次關系的集合
二十五:socket包安全
TCP是一個基于字節流的傳輸服務,“流”意味著TCP所傳輸的數據是沒有邊界的。這不同于UDP提供基于消息的傳輸服務,其傳輸的數據是有邊界的。TCP的發送方無法保證對等方每次接收到的是一個完整的數據包。就會出現分包或粘包的問題
分包:傳輸數據不完整,一條信息被分成多次發送。比如我們發送了一條信息:“你好”,我們可能只收到了“你”,卻沒有收到“好”,這樣就會導致數據的不完整
粘包:傳輸的多條數據粘在一起,比如我發送了“你好”和“我是韓寒”,我們可能會收到“你好我是韓寒”,也可能收到“你好我是”、“你好我”、“你好我是小”,后幾種情況是分包粘包同時發生,我們肯定不希望出現這種現象,所以我們就有必要對我們發生的數據進行編輯
Socket只是一種通信手段它本身沒有任何額外的安全措施,所以要用到加密技術,不然通信的數據非常容易被攻擊者獲取到,一般情況下,我們會使用CRC進行冗余驗證,看數據包是否傳輸完整,然后自定義自己的加密方式,將數據包加密以后再發出,有的項目還會對數據包進行壓縮,所以我們這里給出一種通用的結構:數據頭(長度)+冗余驗證(CRC)+是否壓縮+包體(加密后)
二十六:new和malloc的區別
| 區別 | New delete | malloc free |
| 屬性 | C++編譯器支持 | 庫函數、頭文件支持C |
| 參數 | 申請內存無需指定內存的大小 | 顯示指定大小 |
| 返回值 | 對象類型的指針 | 泛型,void*類型,再轉化為需要的類型 |
| 內存區域 | 自由存儲區 | 堆上動態分配內存 |
二十七:epoll的LT和ET模式的理解
epoll對文件描述符的操作有兩種模式:LT(level trigger)和ET(edge trigger)。LT模式是默認模式,LT模式和ET模式的區別如下:
LT模式:支持block和no-block socket。當epoll_wait檢測到描述符事件發生并將此事件通知應用程序,應用程序可以不立即處理該事件。下次調用epoll_wait時,會再次響應應用程序并通知此事件。效率會低于ET觸發,尤其在大并發,大流量的情況下。但是LT對代碼編寫要求比較低,不容易出現問題。LT模式服務編寫上的表現是:只要有數據沒有被獲取到,內核就不斷通知你,因此不用擔心事件丟失的情況
ET模式:只支持no-block socket。當epoll_wait檢測到描述符事件發生并將此事件通知應用程序,應用程序必須立即處理該事件。如果不處理,下次調用epoll_wait時,不會再次響應應用程序并通知此事件。該模式效率非常高,尤其在高并發,大流量的情況下,會比LT少很多epoll的系統調用。但是對編程要求高,需要細致的處理每個請求,否則容易發生丟失事件的情況
二十八:TCP/UDP的區別
TCP是一種面向連接的,可靠的,基于字節流的傳輸層通信協議,是專門為了在不可靠的網絡中提供一個可靠的端對端字節流而設計的,面向字節流
UDP(用戶數據報協議)是ISO參考模型中一種無連接的傳輸層協議,提供簡單不可靠的非連接傳輸層服務,面向報文
區別:
1.TCP是面向連接的,可靠性強;UDP是基于非連接的,可靠性低
2.由于TCP是連接的通信,需要有三次握手、重新確認等連接過程,會有延時,實時性差,同時過程復雜,也使得其易于攻擊;UDP沒有建立連接的過程,因而實時性較強,也稍安全
3.在傳輸相同大小的數據時,TCP首部開銷20字節;UDP首部開銷8字節,TCP報頭比UDP復雜,故實際包含的用戶數據較少。TCP在IP協議的基礎上添加了序號機制、確認機制、超時重傳機制等,保證了傳輸的可靠性,不會出現丟包或亂序,而UDP有丟包,故TCP開銷大,UDP開銷小?
4.每條TCP連接只能是點到點的;UDP支持一對一、一對多、多對一、多對多的交互通信
應用場景選擇:
對實時性要求高和高速傳輸的場合下使用UDP,在可靠性要求低,追求效率的情況下使用UDP
需要傳輸大量數據且對可靠性要求高的情況下使用TCP
二十九:三次握手和四次揮手
三次握手:客戶端和服務端建立連接需要三次握手
第一次:客戶端向服務端發送報文,向服務器發送連接請求
第二次:服務端向客戶端返回ACK報文,通知客戶端可以連接
第三次:客戶端收到服務端報文,正式連接服務端
三次握手完成
四次揮手:客戶端要與服務器斷開連接,需要四次揮手
第一次:客戶端向服務端發送FIN報文,向服務器發送中斷連接請求
第二次:服務器收到客戶端中斷請求,向客戶端發送已得知中斷請求,但服務器還有資源未處理,需要等待;
第三次:服務器處理完數據后,再次向客戶端發送報文,告訴客戶端可以斷開連接了
第四次:客戶端收到服務端斷開連接的確認信息后,最后發送信息看是否真的斷開連接了,如果服務器一段時間沒有回應,則說明已經斷開了,中斷過程完成
四次揮手完成
三十:socket的概念和特點
socket概念:
這是為了實現以上的通信過程而建立起來的通信管道,其真實的代表是客戶端和服務器端的一個通信進程,雙方進程通過socket進行通信,而通信的規則采用指定的協議
socket只是一種連接模式,不是協議,socket是對TCP/IP協議的封裝,socket本身并不是協議,而是一個調用接口(API),通過socket,我們才能使用TCP/IP協議。TCP、UDP,簡單的說,是兩個最基本的協議,很多其他協議都是基于這兩個協議如,http就是基于TCP的,用socket可以創建TCP連接,也可以創建UDP連接
Socket傳輸的特點:
優點:
1.傳輸數據為字節級,傳輸數據可自定義,數據量小(對于手機應用講;費用低)
2.傳輸數據時間短,性能高
3.適合于客戶端和服務端之間信息實時交互
4.可以加密,數據安全性強
缺點:
1.需對傳輸的數據進行解析,轉化成應用級的數據
2.對開發人員的開發水平要求高
3.相對于http協議傳輸,增加了開發量
三十一:GDB調試
GDB是一個由GNU開源組織發布的,UNIX/LINUX操作系統下的,基于命令行的,功能強大的程序調試工具
進入GDB后可以直接在(gdb)后輸入相應命令進行調試操作
1.啟動gdb
2.查看源碼list
3.運行程序 run
4.設置斷點 break
5.單步執行continue、step、next
6.查看變量 printf
7.退出調試 quit
三十二:面向對象的理解
1.面向對象
特點:被動的去實現,分解成一個個的對象
由現實的世界建立的軟件模型
優點:效率高、易維護、易復用、易擴展
缺點:類調用時需要實例化,開銷比較大
面向對象:面向對象編程就是把問題分解成各個對象,建立對象的目的不是為了完成一個步驟,而是為了描述某個事物在整個解決問題的步驟中的行為
面向對象就是高度實物抽象化(功能劃分)、面向過程就是自頂向下的編程(步驟劃分)
三十三:虛函數的作用
虛函數的作用
用專業術語來解釋就是實現多態性(Polymorphism),多態性說將接口與實現進行分離;用形象的語言來解釋就是實現以共同的方法,但因個體差異而采用不同的策略
虛函數的實現
在有虛函數的類中,類的最開始部分是一個虛函數表的指針,這個指針指向一個虛函數表,表中放了虛函數的地址,實際的虛函數在代碼段(.text)中,當子類繼承了父類的時候也會繼承其虛函數表,當子類重寫父類中虛函數的時候,會將其繼承到的虛函數表中的地址替換為重新寫的函數地址。使用了虛函數,會增加訪問內存開銷,降低效率
三十四:類和對象的關系
類是對象的概括,對象是類的具體實現
1.對象:對象是運行期的基本實體,它是一個封裝了數據和操作這些數據的代碼的邏輯實體
2.類:類是具有相同類型的對象的抽象。一個對象所包含的所有數據和代碼可以通過類來構造
三十五:IO復用,epoll和select的區別,epoll和select的特點
I/O多路復用是為了解決進程或線程阻塞到某個I/O系統調用而出現的技術,使進程或線程不阻塞于某種特定的I/O系統調用
select(),poll(),epoll()都是I/O多路復用的機制,I/O多路復用是通過一種機制,可以監視多個描述符,一旦某個描述符就緒(一般是讀就緒或者是寫就緒,就是這個文件描述符進行讀寫操作之前),能夠通知程序進行相應的讀寫操作
epoll:
epoll支持水平觸發和邊緣觸發,最大的特點在于邊緣觸發,它只告訴進程哪些fd剛剛變為就需態,并且只會通知一次。還有一個特點是,epoll使用“事件”的就緒通知方式,通過epoll_ctl注冊fd,一旦該fd就緒,內核就會采用類似callback的回調機制來激活該fd,epoll_wait便可以收到通知
epoll的優點:
1.沒有最大并發連接的限制,能打開的FD的上限遠大于1024(1G的內存上能監聽約10萬個端口)
2.效率提升,不是輪詢的方式,不會隨著FD數目的增加效率下降。只有活躍可用的FD才會調用callback函數;即epoll最大的優點就在于它只管你“活躍”的連接,而跟連接總數無關,因此在實際的網絡環境中,Epoll的效率就會遠遠高于select和poll
3.內存拷貝,利用mmap()文件映射內存加速與內核空間的消息傳遞;即epoll使用mmap減少復制開銷
select:
select的核心功能是調用tcp文件系統的poll函數,不停的查詢,如果沒有想要的數據,主動執行一次調度(防止一直占用CPU),直到有一個連接有想要的消息為止。從這里可以看出select的執行方式基本就是不同的調用poll,直到有需要的消息為止
缺點:
1.每次調用select,都需要把fd集合從用戶態拷貝到內核態,這個開銷在fd很多時會很大
2.同時每次調用select都需要在內核遍歷傳遞進來的所有fd,這個開銷在fd很多時也很大
3.select支持的文件描述符數量太小了,默認是1024
優點:
1.select的可移植性更好,在某些Unix系統上不支持poll()
2.select對于超時值提供了更好的精度:微秒。而poll是毫秒
三十六:客戶端與服務器如何通信
1.服務器先用socket()函數來建立一個套接字,用這個套接字完成通信的監聽和數據的收發
2.服務器用bind()函數來綁定一個端口號和IP地址,使套接字與指定的端口號和IP地址相關聯
3.用服務器調用listen()函數,使服務器的這個端口和IP處于監聽狀態,等待網絡中某一客戶機的請求發送
4.客戶機用socket()函數建立一個套接字,設定遠程IP和端口
5.客戶機調用socket()函數連接遠程計算機指定的端口
6.服務器調用accept()函數來接受遠程計算機的請求,建立與客戶機之間的通信連接
7.建立連接后,客戶機用write()函數或者close()函數向socket中寫入數據,也可以用read()函數讀取服務器發來的數據
8.服務器用read()函數讀取客戶機發來的數據,也可以用write()函數或者send()函數來發送數據
9.通信完成以后,使用close()函數關閉socket連接
三十七:堆和棧的區別
棧由操作系統自動分配釋放,用于存放函數的參數值、局部變量等,其操作方式類似于數據結構中的棧
堆由開發人員分配和釋放,若是開發人員不釋放,程序結束時由OS回收,分配方式類似于鏈表
堆與棧實際上是操作系統對進程占用的內存空間的兩種管理方式,主要有如下幾種區別:
1.管理方式不同、棧由操作系統自動分配釋放,無需我們手動控制;堆的申請和釋放工作由程序員控制,容易產生內存泄漏
2.空間大小不同,每個進程擁有的棧的大小要遠遠小于堆的大小、理論上,程序員可申請的堆大小為虛擬內存的大小,進程棧的大小64bits的windows默認1MB,64bits的Linux默認10MB
3.生長方向不同,堆的生長方向向上,內存地址由低到高;棧的生長方向向下,內存地址由高到低
4.分配方式不同,堆都是動態分配的,沒有靜態分配的堆,棧有2種分配方式:靜態分配和動態分配。靜態分配是由操作系統完成的,比如局部變量的分配。動態分配由于malloc函數進行分配,但是棧的動態分配和堆是不同的,它的動態分配是由操作系統進行釋放,無需我們手工實現
5.分配效率不同。棧由操作系統自動分配,會在硬件層級對棧提供支持:分配專門的寄存器存放棧的地址,壓棧出棧都有專門的指令執行,這就決定了棧的效率比較高,堆則是由C/C++提供的庫函數或運算符來完成申請和管理,實現機制較為復雜,頻繁的內存申請容易產生內存碎片。顯然,堆的效率比棧要低的多
三十八:結構體和類的區別
最本質的一個區別就是默認的訪問控制:
默認的繼承訪問權限
struct是public的,class是private的
三十九:STL中的vector是如何實現的
STL(Standard Template Library),即標準模板庫,是一個具有工業強度的,高效的C++程序庫,它被容納于C++標準程序庫中,包括容器、算法、迭代器組件。vector內部使用動態數組的方法實現的。如果動態數組的內存不夠用,就要動態地重新分配,一般是當前大小的兩倍,然后把原數組的內容拷貝過去。所以,在一般情況下,其訪問速度同一般數組,只有在重新分配發生時,其性能才會下降。注意vector的size()和capacity()是不同的,前者表示數組中元素的多少,后者表示數組有多大的容量。由上面的分析可以看出,使用vector的時候需要注意內存的使用,如果頻繁地進行內存地重新分配,會導致效率低下。它的內部使用allocator類進行內存管理,程序員不需要自己操作內存
vector其中一個特點:內存空間只會增長,不會減小,援引C++ Primer:為了支持快速的隨機訪問,vector容器的元素以連續的方式存放,每一個元素都緊挨著前一個元素存儲。設想一下,當vector添加一個元素時,為了滿足連續存放這個特性,都需要重新分配空間、拷貝元素、撤銷舊空間?,這樣性能難以接受。因此STL實現者在對vector進行內存分配時,其實際分配的容量要比當前所需的空間多一些。就是說,vector容器預留了一些額外的存儲區,用于存放新添加的元素,這樣就不必為每個新元素重新分配整個容器的內存空間
四十:如何保證線程的安全
在大多數軟件應用中,線程的數量都不止一個,多線程程序處在一個多變的環境中,可以訪問的全局變量和堆數據隨時都可能被其他的線程改變,這就將”線程安全“的問題提上了議程。那么,如何確保線程的安全呢?
線程安全
一般來說,確保線程安全的方法有這幾個:競爭與原子操作、同步與鎖、可重入、過度優化
競爭與原子操作
多個線程同時訪問和修改一個數據,可能造成很嚴重的后果。出現嚴重后果的原因是很多操作被操作系統編譯為匯編代碼之后不止一條指令,因此在執行的時候可能執行了一半就被調度系統打斷了而去執行別的代碼了。一般將單指令的操作稱為原子的(Atomic),因為不管怎樣,單條指令的執行是不會被打斷的
因此,為了避免出現多線程操作數據的出現異常,Linux系統提供了一些常用操作的原子指令,確保了線程的安全。但是,它們只適用于比較簡單的場合,在復雜的情況下就要選用其他的方法了
同步與鎖
為了避免多個線程同時讀寫一個數據而產生不可預料的后果,開發人員要將各個線程對同一個數據的訪問同步,也就是說,在一個線程訪問數據未結束的時候,其他線程不得對同一個數據進行訪問
同步的最常用的方法是使用鎖(Lock),它是一種非強制機制,每個線程在訪問數據或資源之前首先試圖獲取鎖,并在訪問結束之后釋放鎖;在鎖已經被占用的時候試圖獲取鎖時,線程會等待,直到鎖重新可用
二元信號量是最簡單的一種鎖,它只有兩種狀態:占用與非占用,它適合只能被唯一一個線程獨占訪問的資源。對于允許多個線程并發訪問的資源,要使用多元信號量(簡稱信號量)
可重入
一個函數被重入,表示這個函數沒有執行完成,但由于外部因素或內部因素,又一次進入該函數執行。一個函數稱為可重入的,表面該函數被重入之后不會產生任何不良后果。可重入是并發安全的強力保障,一個可重入的函數可以在多線程環境下放心使用
過度優化
在很多情況下,即使我們合理地使用了鎖,也不一定能夠保證線程安全,因此,我們可能對代碼進行過度的優化以確保線程的安全
四十一:數組和鏈表的區別
數組
數組的特點
1.在內存中,數組是一塊連續的區域
2.數組需要預留空間
在使用前需要提前申請所占內存的大小,這樣不知道需要多大的空間,就預先申請可能會浪費內存空間,即數組空間利用率低
ps:數組的空間在編譯階段就需要進行確定,所以需要提前給出數組空間的大小(在運行階段是不允許改變的)
3.在數組起始位置處,插入數據和刪除數據效率低
插入數據時,待插入位置的元素和它后面的所有元素都需要向后搬移
刪除數據時,待刪除位置后面的所有元素都需要向前搬移
4.隨機訪問效率很高,時間復雜度可以達到O(1)
因為數組的內存是連續的,想要訪問那個元素,直接從數組的首地址向后偏移就可以訪問了
5.數組開辟的空間,在不夠使用的時候需要擴容,擴容的話,就會涉及到需要把舊數組中的所有元素向新數組中搬移
6.數組的空間是從棧分配的
數組的優點
隨機訪問性強,查找速度快,時間復雜度為O(1)
數組的缺點
1.頭插和頭刪的效率低,時間復雜度為O(N)
2.空間利用率不高
3.內存空間要求高,必須有足夠的連續的內存空間
4.數組空間的大小固定,不能動態拓展
鏈表
鏈表的特點
1.在內存中,元素的空間可以在任意地方,空間是分散的,不需要連續
2.鏈表中的元素都會兩個屬性,一個是元素的值,另一個是指針,此指針標記了下一個元素的地址
每一個數據都會保存下一個數據的內存的地址,通過此地址可以找到下一個數據
3.查找數據時效率低,時間復雜度為O(N)
因為鏈表的空間是分散的,所以不具有隨機訪問性,如果需要訪問某個位置的數據,需要從第一個數據開始找起,依次往后遍歷,直到找到待查詢的位置,故可能在查找某個元素時,時間復雜度達到O(N)
4.空間不需要提前指定大小,是動態申請的,根據需求動態的申請和刪除內存空間,擴展方便,故空間的利用率較高
5.任意位置插入元素和刪除元素效率較高,時間復雜度為O(1)
6.鏈表的空間是從堆中分配的
鏈表的優點
1.任意位置插入元素和刪除元素的速度快,時間復雜度為O(1)
2.內存利用率高,不會浪費內存
3.鏈表的空間大小不固定,可以動態拓展
鏈表的缺點
隨機訪問效率低,時間復雜度為O(N)
四十二:boost庫是否有了解
boost庫是一個優秀的,可移植,開源的C++庫,它是由C++標準委員會庫工作自成員發起,它是對STL的延續和擴充,設計理念和STL比較接近,都是利用泛型讓復用達到最大化,其中有些內容經常成為下一代C++標準庫內容,在C++社區影響很大,是不折不扣的“準”標準庫
四十三:socket的工作模式,為什么選擇socket
socket是對tcp/ip協議的封裝和應用,給我們提供了操作網絡的接口
工作模式:
阻塞模式:是socket的缺省方式,也是最常用的方式,即函數阻塞直到調用完畢
可能造成阻塞的函數有:connect()、accept()、讀寫函數、select()、poll()等
非阻塞模式:非阻塞IO通過進程反復調用IO函數(多次系統調用,并且馬上返回);在數據拷貝的過程中,進程是阻塞的
I/O多路復用(同步I/O模式):使用select()、poll()等函數實現對多個socket的同步I/O操作。它能同時等待多個socket描述符,而這些socket描述符其中的任意一個進入讀就緒/寫就緒/出錯狀態
為什么選擇socket
應用層通過傳輸層進行數據通信時,TCP和UDP會遇到同時為多個應用程序進程提供并發服務的問題。多個TCP連續或多個應用程序進程可能需要通過同一個TCP協議端口傳輸數據。為了區別不同的應用程序進程和連接,許多計算機操作系統為應用程序與TCP/IP協議交互提供了稱為套接字(socket)的接口,區分不同應用程序進程間的網絡通信和連接
四十四:長連接和短連接
短連接
連接->傳輸數據->關閉數據
HTTP是無狀態的,瀏覽器和服務器每進行一次HTTP操作,就建立一次連接,但任務結束后就中斷連接。短連接是指socket連接后發送后接收完數據后馬上斷開連接
長連接
連接->傳輸數據->保持連接->傳輸數據->...->關閉連接
長連接指建立socket連接后不管是否使用都保持連接,但安全性較差
四十五:socket中阻塞和非阻塞的區別
非阻塞模式可以理解為,執行此套接字的網絡調用時,不管是否執行成功,都會立即返回
如調用recv()函數讀取網絡緩沖區中的數據時,不管是否讀到數據都立即返回,而不會一直掛在此函數的調用上
而阻塞模式為只有接收到數據后才會返回,套接字默認的會創建阻塞模式
四十六:QT的信號槽機制的理解
Qt提供信號和槽機制用于完成界面操作的響應,是完成任意兩個Qt對象之間的通信機制。其中,信號會在某個特定情況或動作下被觸發,槽是等同于接收并處理信號的函數
信號槽機制與回調的區別
1.回調函數的本質是“你想讓別人的代碼執行你的代碼,而別人的代碼你又不能動“這種需求下產生的。回調函數是函數指針的一種用法,如果多個類都關注某個類的狀態變化,此時需要維護一個列表,以存放多個回調函數的地址。對于每一個被關注的類,都需要做類似的工作,因此這種做法效率低,不靈活
2.Qt使用信號和槽機制來解決這個問題,程序員只需要指定一個類含有哪些信號函數、哪些槽函數,Qt會處理信號函數和槽函數之間的綁定。當信號函數被調用時,Qt會找到并執行與其綁定的槽函數。允許一個信號函數和多個槽函數綁定,Qt會依次找到并執行與一個信號函數綁定的所有槽函數,這種處理方式更加靈活
3.Qt信號與槽機制降低了Qt對象的耦合度。激發信號的Qt對象無需知道是哪個對象的哪個槽需要接收它發出的信號,它只需要做的是在適當的時間發送適當的信號就可以了,而不需要知道也不關心它的信號有沒有被接收到,更不需要知道哪個對象的哪個槽接收到了信號。同樣地,對象的槽也不知道是哪些信號關聯了自己,而一旦關聯信號和槽,Qt就保證了適合的槽得到了調用。即使關聯的對象在運行時被刪除。應用程序也不會崩潰
四十七:Qt的線程的使用
QThread類提供了一個與平臺無關的管理線程的方法。一個QThread對象管理一個線程。QThread的執行從run()函數的執行開始,在Qt自帶的QThread類中,run()函數通過調用exec()函數來啟動事件循環機制,并且在線程內部處理Qt的事件。在Qt中建立線程的主要目的就是為了用線程來處理那些耗時的后臺操作,從而讓主界面能及時響應用戶的請求操作
1.自定義一個繼承QThread的類MyThread,重載MyThread中的run()函數,在run()函數中寫入需要執行的工作
2.調用start()函數來啟動線程
四十八:QT樣式表和選擇器
Qt樣式表是另外一種自定義部件外觀的機制,使用樣式表可以更方便的設置界面的外觀,而不用去子類化QStyle類
四十九:Qt的STL和C++的STL有什么區別
C++中容器類是屬于標準模板庫中的內容Qt提供了它自己的一套容器類,這就是說,在Qt的應用程序中,我們可以使用標準C++的STL,也可以使用Qt的容器類。Qt容器類的好處在于,它提供了平臺無關的行為,以及隱式數據共享技術
區別
1.STL的vector最開始分配的空間是1個,而QVector開始分配的空間為4個(可見Qt在空間分配上的優化)
2.STL的vector發生超過容量本身的訪問,并不一定失敗(因為內存可能足夠大并存在),而QVector則發生了斷言錯誤。而顯然,第二種處理方式會更好。而第一種可能會造成莫名其妙的錯誤,尤其是當工程師忘記vector的范圍,而vector本身并不出錯的時候
顯然,Qt的容器基于STL進行了升級。如果有類似于Qt的容器之類的容器,優先選擇更好的容器;而如果使用STL,要知道STL這種特點,并避免這類事情的發生
五十:什么是野指針
野指針
指向內存被釋放的內存或者沒有訪問權限的內存的指針
”野指針“的成因主要有3種
1.指針變量沒有被初始化
2.指針p被free或者delete之后,沒有置為NULL
3.指針操作超越了變量的作用范圍
五十一:長連接和短連接
短連接
連接->傳輸數據->關閉連接
HTTP是無狀態的。瀏覽器和服務器每進行一次HTTP操作,就建立一次連接,但任務結束后就中斷連接。
短連接是指socket連接后發送后接收完數據后馬上斷開連接
長連接
連接->傳輸數據->保持連接->傳輸數據->...->關閉連接
長連接指建立socket連接后不管是否使用都保持連接,但安全性較差
五十二:客戶端掉線和服務端掉線檢測
socket中用心跳包檢測客戶端與服務端掉線狀況
心跳包:
它像心跳一樣每隔固定時間發一次,以此來告訴服務器,這個客戶端還活著。事實上這是為了保持長連接,至于這個包的內容,是沒有什么特別規定的,不過一般都是很小的包,或者只包含包頭的一個空包。
心跳檢測步驟
1.客戶端每隔一個時間間隔發送一個探測包給服務器
2.客戶端發包時啟動一個超時定時器
3.服務器端接收到檢測包,應該回應一個包
4.如果客戶機收到服務器的應答包,則說明服務器正常,刪除超時定時器
5.如果客戶端的超時定時器超時,依然沒有收到應答包,則說明服務器掛了
五十三:哈希表有什么特點
哈希表(Hash Table,也叫散列表),是根據關鍵碼值(Key-Value)而直接進行訪問的數據結構,也就是說,它通過把關鍵碼值映射到表中一個位置來訪問記錄,以加快查找的速度。哈希表的實現主要需要解決兩個問題,哈希函數和沖突解決
特點
1.哈希表的查找效率主要取決于構造哈希表時選取的哈希函數和處理沖突的方法
2.在各種查找方法中,平均查找長度與節點個數n無關的查找方法是哈希表查找法
3.哈希函數取值是否均勻是評價哈希函數好壞的標準
4.哈希存儲方法只能存儲數據元素的值,不能存儲數據元素之間的關系
5.哈希表的裝填因子a<1,并不可以避免沖突的產生
五十四:子進程繼承父進程的哪些資源
在Linux系統內,創建子進程的方法是使用系統調用fork()函數,fork()函數是Linux系統內一個非常重要的函數,它與我們之前學過的函數有一個顯著的區別:fork()函數調用一次卻會得到兩個返回值
fork()函數用于從一個已經存在的進程內創建一個新的進程,新的進程稱為”子進程“,相應的稱創建子進程的進程為”父進程“
使用fork()函數得到的子進程是父進程的復制品,子進程完全復制了父進程的資源,包括進程上下文,代碼區,數據區,堆區,棧區,內存信息,打開文件的文件描述符,信號處理函數,進程優先級,進程組號,當前工作目錄,根目錄,資源限制和控制終端等信息,而子進程與父進程的區別有進程號,資源使用情況和計時器等
五十五:為什么選擇共享內存
共享內存
顧名思義就是允許兩個不相關的進程訪問同一個邏輯內存,共享內存是兩個正在運行的進程之間共享和傳遞數據的一種非常有效的方式
優點
我們可以看到使用共享內存進行進程之間的通信是非常方便的,而且函數的接口也比較簡單,數據的共享還使進程間的數據不用傳送,而是直接訪問內存,加快了程序的效率
五十六:Linux下如何調試
邏輯錯誤用log
內存錯誤用gdb
單元測試用gtest
編譯器用clang
log框架用log4cplus
性能熱點用gprof
五十七:大量客戶端連上來,服務器如何處理
這時候服務器端應該使用多線程,每連接上一個客戶端就給該客戶端開啟一個線程。監聽端口的時候也要單獨開一個線程、不然會阻塞主線程。這樣做有一個明顯的缺點,就是有N個客戶端請求連接時,就會有N個線程,對程序的性能和計算機的性能影響很大,可以使用線程池進行管理
使用線程池的好處
主要用于減少因頻繁創建和銷毀線程帶來的開銷,因此那些經常使用且執行時間短的 線程需要用線程池來管理
五十八:HTTP協議
對客戶端和服務器之間數據傳輸的格式規范,格式簡稱為”超文本傳輸協議”
五十九:大端模式和小端模式
主機字節序就是我們平常說的大端和小端模式:不同的CPU有不同的字節序類型,這些字節序是指整數在內存中保存的順序,這個叫做主機序
引用標準的Big-Endian和Little-Endian的定義如下
1.Little-Endian就是低位字節排放在內存的低地址端,高位字節排放在內存的高地址端
2.Big-Endian就是高位字節排放在內存的低地址端,低位字節排放在內存的高地址端
六十:C++靜態庫和動態庫的區別
二者的不同點在于 代碼被載入的時刻不同
靜態庫
在程序編譯時會被連接到目標代碼中,程序運行時將不再需要該靜態庫,因此體積較大
動態庫
在程序編譯時并不會被連接到目標代碼中,而是在程序運行時才被載入,因此在程序運行時還需要動態庫存在,因此代碼體積較小
動態庫的好處
不同的應用程序如果調用相同的庫,那么在內存里只需要有一份該共享庫的實例
六十一:雙向鏈表如何實現
雙向循環鏈表
即在單鏈表(上文描述的鏈表為單鏈表)的基礎上進行改進,每個節點不光有存儲下一個節點地址的指針域next,還增加了存儲上一個節點地址的指針域prev,其中頭(第一個節點)的prev指向尾節點(最后一個節點),尾節點的next指向頭節點
實現:
在操作時創建temp指針指向鏈表中各元素,更改prev及next指向的節點就可以實現對鏈表的基本增刪查改等操作
六十二:FFmpeg如何實現編碼
編碼思路分析
1.注冊所有的組件
2.根據需要的碼流數據的格式,來猜測的需要的編碼器
3.打開目標文件流
4.新建視頻流
5.設置編碼器上下結構的一系列參數,為編碼做好準備
6.查找對應的編碼器
7.打開編碼器
8.讀取普通視頻數據or攝像頭數據,進行解碼,保證得到的是YUV的像素數據
9.先寫入編碼的頭部信息
10.正式開始,進行編碼,將一幀像素數據壓縮成碼流數據
11.保存寫入文件中
12.得到最終的編碼后的碼流數據
六十三:FFmpeg如何實現解碼
解碼思路分析
1.注冊所有組件 av_register_all()
2.打開視頻文件 avformat_open_input()有可能打開失敗
3.獲取視頻信息 視頻碼流 音頻碼流 文字碼流
4.查找流信息 avformat_find_stream_info()
5.找到解碼器 avcodec_find_decoder()有可能沒找到
6.打開解碼器 avcoedec_open2()
7.讀取碼流中的一幀碼流數據 av_read_frame()
8.解碼讀取到一幀碼流數據 得到一幀的像素數據YUV RGB
9.重復7-8的動作,直到視頻所有的幀都處理完
10.關閉解碼器
11.關閉視頻文件
六十四:FFmpeg如何實現轉碼
轉碼思路分析
1.注冊組件
2.打開視頻流 打開視頻文件
3.查找有沒有流數據
4.查找視頻碼流數據
5.根據需要的封裝格式,來猜測格式對應編輯器
6.打開對應文件
7.新建流
8.寫入頭部信息
9.讀取一幀一幀的碼流數據
10.轉碼 --->時間基的轉化
11.寫入對應的一幀數據到文件中
六十五:MVC框架
MVC框架能夠將業務進行分離,數據和界面進行分離,在團隊項目中容易分工各個模塊給不同的人員
使得MVC架構模擬用戶登錄的流程
舉例 用戶登錄界面:
1.發送請求到控制器
2.控制器委托用戶模型去做用戶數據的查詢
3.用戶模型查詢用戶表得到結果
4.用戶模型把查詢到的結果返回給控制器
5.控制器將用戶模型返回的結果反饋給用戶登錄界面
MVC的優點
代碼模塊化,分工明確,提高工作效率。耦合性低,增加了組件的重用性,降低了維護成本
MVC的缺點
系統結構復雜,實現起來比較困難,所以小型項目不適用,只適合大型項目,view和controller聯系過于緊密,MVC將其分離,導致應用的范圍會受到限制,雖然MVC對代碼進行了模塊化處理,但是由于關聯性,很難實現獨立重用
?
總結
以上是生活随笔為你收集整理的【C++软件开发】面试经典题目汇总的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: wordpress实现搜索页关键词高亮
- 下一篇: 文章观后感