騰訊事務型開發面試

騰訊電話一面

1、malloc 和 new 的區別?

malloc 是一個庫函數,而 new 是C++11 新引進的關鍵字,不過 new 的底層也是一個 malloc 函數,相當於對 malloc 進行了封裝,另外 malloc 函數返回值是 void*,所以需要強佔類型轉化,對於 new 是可以指定類型返回的,在申請的時候,malloc 需要指定特定的字節數去申請,那麼 new 可以直接通過類型去推導出申請多個字節,所以 new 使用起來更加方便點

對於申請內置類型,malloc 和 new 區別不大,但是如果申請的自定義類型,在創建對象的時候會調用構造函數,那麼 new 它是通過調用 operator new 函數去申請的,如果申請成功返回,申請失敗則拋出一個異常,operator new 它的底層依然是通過 malloc 去向內存申請資源.

2、引用和指針的區別,使用場景?

引用本身就是一個實體,也可以理解爲一個別名,而指針是通過一個指針變量去指向內存中的一塊資源,引用可以直接對實體操作,而指針是通過解引用的方式去操作,而且可能會發生內存錯誤的問題,所以引用使用起來比指針更加安全.

對引用求字節數,比如 sizeof 函數,得出來的結果是實體所佔的字節數,而指針在 32 和 64 位系統分別是 4 個字節和 8 個字節,引用不可爲空,它一定是要指向一個實體,而指針可以爲空,另外指針也存在二級指針,三級指針…,引用是不存在的

使用場景:在給變量起別名的時候,也可以將引用作爲函數的形參,比如在拷貝構造函數的時候,傳入的是一個引用形參,另外也可以將引用作爲函數的返回值,通過傳引用的方式可以減少開銷;如果對象時一個數組的時候,在進行傳入參數使用指針去傳入首地址就可以了,另外如果對象是一個結構體,那麼也可以通過指針的方式傳入

3、vector 使用過嗎?仿函數是什麼?迭代器失效原理,爲什麼會失效?

vector 是 STL 中的序列式容器,底層是一個動態的數組,在進行訪問的時候是以 O(1) 的時間複雜度,因爲是它一塊連續的內存,可以直接通過下標去訪問,主要的使用場景就是查找訪問次數多的情況,對於插入和刪除的情況可以使用 list 容器,它的底層結構是雙向鏈表,所以在插入和刪除方面是高效的.

迭代器是相當於一個工具,它在不知道容器內部的結構情況下,遍歷容器內的元素,vector 在插入的一個元素的時候可能會導致迭代器失效,比如插入元素的時候需要擴容,那麼擴容就可能導致所有的迭代器失效,在刪除的時候,會導致後面的迭代器失效

迭代器之所以失效,是因爲一些操作影響了元素的位置,就比如一組數據 1 2 3 4 5 6 7 8 9 ,假如此時迭代器指向的是 6 元素,如果把 6 刪除後,6 後面的元素就會向前走,對迭代器進行操作的時候就會導致內存訪問錯誤,正確的做法應該是讓迭代器賦值到指向 7 的元素.

4、在使用容器的時候,如何分配空間的?

通過空間配置器,空間配置器可以分爲兩級,一級是對比較大的內存,比如大於 128k 進行處理,它是通過對 malloc 進行了封裝,然後去內存中申請資源,如果申請成功的話返回,如果失敗會拋出一個異常,對於二進空間配置器,它是通過內存池來實現的,內存池是首先向內存中申請一大塊內存,然後用戶需要的時候直接去內存池取就可以了,使用完內存還給內存池,這樣做可以避免頻繁的申請內存而導致內存碎片所帶來得空間資源浪費

5、排序問題,冒泡排序和快速排序如何實現?各自的時間複雜度,最壞情況的時間複雜度?

冒泡排序是通過比較相鄰的兩個元素,如果兩個元素不滿足規則就進行交換,每一對相鄰的元素都做同樣的工作,一般有兩種情況,一種是向上排序,一種是向下排序,將最大的由元素或者最小的元素排在前面或者後面.

冒泡法最好的時間複雜度是O(N),最壞是O(N2)

快速排序是通過劃分基準值的方式,左邊所有的元素比基準值小,右邊所有的元素比基準值大,然後通過遞歸的方式分別對左右兩邊進行同樣的操作,直到整個數據有序.時間複雜度爲N*log(N),最壞爲O(N2)

6、淺拷貝和深拷貝,所有的淺拷貝都是多個對象使用一個資源嗎?深拷貝是一個對象佔用一個資源?

淺拷貝是在拷貝的過程中,將值和地址一起拷貝過去,那麼就會導致多個對象指向同一塊內存,例如類中的默認拷貝構造函數就是一種淺拷貝的方式,使用起來是比較危險的,可以通過深拷貝的方式來解決淺拷貝帶來的問題

深拷貝的意思是兩個指針或對象指向的不同的內存資源,他們之間是獨立的並不共享內存,這樣可以避免釋放資源的時候發生錯誤

當然也有一種方法,可以解決淺拷貝的問題,就是採用寫時拷貝,它的本質是一個引用計數器,對於構造的時候會對計數器 +1,然後釋放的時候會 -1 操作,只有當這個計數器值爲 0 的時候,然後纔會釋放資源,另外關於寫時拷貝在讀取的時候,如果不需要對內存進行操作那麼就不進行拷貝,如果需要進行操作內存的時候,就會爲操作的對象拷貝一份資源,這樣可以無論它怎麼修改,都不會影響到原來的內存,既保證了安全性,也提高大量拷貝帶來的開銷.

7、static 關鍵字用法?

static 修飾局部變量,全局變量,函數,類中的成員變量,類中的成員函數

修飾局部變量的時候,生命週期邊長,本來局部變量在函數調用完成之後就會釋放,現在它隨着整個程序結束後纔會釋放,作用域是不變的,static 修飾全局變量的時候作用域變小,本來是源程序的作用域,經過修飾後變爲當前文件可見,生命週期不變,當修飾普通函數的時候和全局變量類型,只對當前文件可見

修飾類中的成員變量時,存儲在全局數據區,不屬於某個對象而是屬於整個類,初始化的時候就會分配內存空間,對所有的對象共享,修飾成員函數的時候,稱爲靜態成員函數,裏面沒有 this 指針,所以不會修改成員變量,同樣被所有的對象共享,並不屬於某一個對象,另外靜態成員函數不可以調用非靜態的成員函數.

8、const 使用方法以及常用的使用場景?

const 可以指定一個變量不可以被修改,有三種寫法,當 const 寫在最前面的時候,指定的時候變量的值不可以被修改,如果寫在最後面的時候,表示指針的指向不可以修改,寫在中間和前面的功能是一樣的.另外在傳入參數的時候可以使用 const 保證變量的安全

9、map 容器,底層原理,key 可以重複嗎?

map 底層結構紅黑樹,通過鍵值對的形式存儲元素,key 是不可以重複的,如果重複的話可以使用 multimap 容器,對於 map 也自帶排序的功能,查找起來也比較快,是 log(N)的時間複雜度.

10、二叉樹有了解嗎?

二叉樹有很多種類,比如二叉搜索樹,它的時間複雜度是O(N),因爲會有極端的情況出現,所謂爲了避免這種情況,引入了 AVL 樹,它在搜索樹的基礎上增加了平衡因子,可以保證二叉搜索樹的平衡,時間複雜度降低到 O(logN),但是由於需要進行旋轉,所以會帶來很大的開銷,那麼又引入紅黑樹,它不是絕對的平衡,根據自己的特性,比如一個節點只能不是紅色就是黑色,根節點和葉子節點都是黑色這種特性,保證旋轉的次數被大大的減少,但是它的查找時間複雜度依然是O(logN)

11、進程間通信方式?

進程之間通過通信可以傳輸文件,傳送信息,那麼可以通過管道來進行通信,管道是半雙工的通信方式,管道分爲匿名管道和命名管道,匿名管道它只能允許親緣進程之間的通信,而命名管道則不受限制,它們都有共同的特性和讀寫規則

當管道沒有數據的時候,不可以讀,當數據滿的時候,不可以寫,如果對應的寫文件描述符被關閉,則讀的時候 read 函數會返回0,如果讀端被關閉,則寫的時候,寫端會觸發異常

另外我覺得管道就是一塊內存的緩衝區構成的一個隊列,使用一對文件描述符來訪問這個內存,讀文件描述符就是往隊列中取數據,寫文件描述符就是往隊列中插入數據

它的缺陷是效率比較低,而且如果數據沒有取出,則不會返回,所以可以使用消息隊列

消息隊列是內核維護的一個隊列,發送信息的一端往隊列中插入信息,接收的一端從隊列中取走數據就可以了,消息隊列傳輸的是有類型的數據塊節點,它的缺陷是需要從內核態到用戶態之間的拷貝,效率依然不是很高,所以可以使用共享內存的通信方法

共享內存它不需要數據拷貝,只需要各個進程的虛擬地址空間映射到相同的物理地址空間就可以了,然後通過共享出來的內存進行通信

大致可以分爲五個步驟,創建共享內存,將共享內存映射到虛擬地址空間,通過虛擬地址空間進行內存的訪問與操作,如果不需要通信的時候,就解除映射關係,最後釋放共享內存.

由於共享內存不需要用戶態到內核態,以及內核態到用戶態之間的數據拷貝,所以它是進程間最快的通信方式

但是需要注意的時候,共享內存並沒有實現同步的機制,那麼就可以使用信號量進行通信

信號量它的本質是維護了一個計數器,可以保證多進程之間的同步與互斥,例如信號量的初始值爲1,當一個進程佔用資源的時候,會將值設爲0,意味着其他進程不可以訪問資源,然後當內存資源被釋放的時候,值變爲1,這個時候其他進程就可以訪問資源

上述的四種通信方式,僅僅限於同一臺主機,如果想要實現對端之間的通信,那麼可以使用套接字的通信方式

套接字通過網絡中的協議對數據進行組裝,然後發送,就比如 http 協議,將數據封裝爲發送報文,然後傳送給傳輸層,可以使用 tcp 或者 udp 協議將數據發送給 IP端,ip 協議可以實現端與端之間的通信.

12、網絡接口的 apl 函數有哪些?

通過 socket 創建套接字,然後客戶端通過 connect 函數與服務器建立連接,服務器在建立連接之前,需要先調用 listen 函數進行監聽,並且通過 bind 函數綁定IP地址和端口號,當服務器收到連接請求後,服務器通過 accept 函數從已完成的隊列中獲取一個客戶端請求,然後如果客戶端發送消息的時候,可以通過 send 函數發送給服務器,那麼服務器通過 recv 函數進行接收.最後通過 close 函數可以關閉套接字

13、數據庫事務?

數據庫的事務就是,系統對數據進行一系列的訪問與更新操作,而這些操作組成一個程序的執行邏輯單元,一共有四大特性

原子性保證的是,該操作要麼成功,要麼失敗,不會執行到一半,一致性指的是事務的開始和結束沒有破壞整個數據庫的完整性,隔離性指的是當多個用戶併發操作數據庫的時候,可以保證其安全性,最後一個是持久性,當數據提交到數據庫的時候,是永久的

數據庫通過隔離級別來解決讀的問題,MySQL的默認隔離級別是可重複讀,它可以避免髒讀,和不可重複讀帶來的影響,髒讀也就是讀取了未提交的數據,不可重複讀針對的是對數據進行了修改的操作,但是默認隔離級別不可以解決幻讀的問題,幻讀主要針對的是插入和刪除時導致的問題,解決幻讀可以通過可串行化讀,在讀取的時候需要鎖住了整張表.所以效率是比較低的.

14、數據庫的索引?

數據庫索引它是對一列或者多列進行排序的一種結構,它的底層是 B+ 數,有的也是哈希結構,索引的目的是提高數據的檢索速度,當然不同的索引也有不同的特性

普通索引,它沒有限制,單純的就是爲了提高數據的檢索,唯一索引它的值必須是唯一的,可以保證記錄數據每一行的唯一性,對於主鍵索引,它是一種特殊的唯一索引,只要體現在一張表只能有一個主鍵索引,且不爲空,另外還有組合索引,組合索引可以覆蓋多個列

15、數據庫表的排序關鍵字、求和關鍵字?

distinct 可以去重,like 進行匹配,desc 降序,asc 是升序,查詢總數 count,數據的更新 update ,數據的刪除 delete

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章