[c/c++后臺(tái)開發(fā)面經(jīng)] 京東面經(jīng)(含答案)
掃描二維碼
隨時(shí)隨地手機(jī)看文章
此系列內(nèi)容以及觀點(diǎn)僅個(gè)人感受,不妥之處直接私我!目的為了大家能更好的知道面試題難度以及如何準(zhǔn)備,希望能讓大家少浪費(fèi)時(shí)間尋找資料,多點(diǎn)時(shí)間學(xué)點(diǎn)干貨!因?yàn)槠?,大部分題目題解簡潔,但有相關(guān)資料推薦進(jìn)階閱讀,學(xué)會(huì)使用搜索引擎是一門藝術(shù)!望諒解!
當(dāng)時(shí)投遞的時(shí)候,崗位只是說了是c/c++開發(fā)工程師,到了二面問了面試官才知道我面的是無人駕駛部門。
一 面試情況
此戰(zhàn)終結(jié)于技術(shù)面最后一面,值得深思。由于內(nèi)推簡歷沒有直接通過篩選,參加了筆試才并有幸參加了面試,但是一面電話面結(jié)束后,面試官說如果有二面希望能現(xiàn)場面!
1 一面(電話面25分鐘)
簡述一下項(xiàng)目
一面提項(xiàng)目,一般說明項(xiàng)目背景,自己做了什么就好了,不會(huì)深問,但是能準(zhǔn)備著更好
項(xiàng)目中遇到過什么問題,怎么解決
這個(gè)問題,凡是涉及項(xiàng)目基本上都跑不了,前面說過需要準(zhǔn)備幾個(gè)面試官百分之80會(huì)問的關(guān)于項(xiàng)目的題。
都學(xué)過什么課程,計(jì)算機(jī)方向是軟件工程嗎
計(jì)算機(jī)網(wǎng)絡(luò),數(shù)據(jù)結(jié)構(gòu),操縱系統(tǒng),編譯原理,人工智能,大數(shù)據(jù)等隨便你選幾個(gè),保證自己能說出個(gè)123
C++中的類的大小計(jì)算
C++中類的成員函數(shù),靜態(tài)成員是不占類的大小的。類的大小等于基類的大小+子類個(gè)non-static成員變量的大小再+非虛基類大小,如果有多態(tài)性還要考慮vptr(可能不止一個(gè))大小,這里成員變量是會(huì)被字節(jié)對(duì)齊的。
介紹一下http與https及區(qū)別
HTTPS和HTTP的區(qū)別
超文本傳輸協(xié)議HTTP協(xié)議被用于在Web瀏覽器和網(wǎng)站服務(wù)器之間傳遞信息。HTTP協(xié)議以明文方式發(fā)送內(nèi)容,不提供任何方式的數(shù)據(jù)加密,如果攻擊者截取了Web瀏覽器和網(wǎng)站服務(wù)器之間的傳輸報(bào)文,就可以直接讀懂其中的信息,因此HTTP協(xié)議不適合傳輸一些敏感信息,比如信用卡號(hào)、密碼等。(此處可以使用wireshark工具模擬模擬,另外如果學(xué)習(xí)協(xié)議也可以考慮python的scapy/dpkt庫)
為了解決HTTP協(xié)議的這一缺陷,需要使用另一種協(xié)議:安全套接字層超文本傳輸協(xié)議HTTPS。為了數(shù)據(jù)傳輸?shù)陌踩?,HTTPS在HTTP的基礎(chǔ)上加入了SSL協(xié)議,SSL依靠證書來驗(yàn)證服務(wù)器的身份,并為瀏覽器和服務(wù)器之間的通信加密。
HTTPS和HTTP的區(qū)別主要為以下四點(diǎn):
一、https協(xié)議需要到ca申請(qǐng)證書,一般免費(fèi)證書很少,需要交費(fèi)。
二、http是超文本傳輸協(xié)議,信息是明文傳輸,https則是具有安全性的ssl加密傳輸協(xié)議(當(dāng)然不是絕對(duì)安全,也可以通過特征抽取,過濾,篩選,模型訓(xùn)練進(jìn)行搞事情!)。
三、http和https使用的是完全不同的連接方式,用的端口也不一樣,前者是80,后者是443。
四、http的連接很簡單,是無狀態(tài)的;HTTPS協(xié)議是由SSL+HTTP協(xié)議構(gòu)建的可進(jìn)行加密傳輸、身份認(rèn)證的網(wǎng)絡(luò)協(xié)議,比http協(xié)議安全。
打印int時(shí)不小心用了%s會(huì)出現(xiàn)什么問題
段錯(cuò)誤
int i = 10;
char *s = "12";
printf("%d\n", s); // 數(shù)據(jù)不對(duì)
printf("%s\n", i); // 段錯(cuò)誤
鏈表成環(huán)(快慢指針,提供思路即可,《劍指offer》)
邏輯題
1000瓶無色無味的藥水,其中有一瓶毒藥,10只小白鼠拿過來做實(shí)驗(yàn)。喝了無毒的藥水第二天沒事兒,喝了有毒的藥水后第二天會(huì)死亡。如何在一天之內(nèi)(第二天)找出這瓶有毒的藥水?
思路就是用二進(jìn)制,2^10=1024,也就是10只小白鼠最多能驗(yàn)出1024瓶藥水,哪個(gè)有毒。小白鼠編號(hào),1-10。瓶子也編號(hào),1-1000,然后把瓶子的編號(hào)轉(zhuǎn)變?yōu)槎M(jìn)制數(shù)。如果第幾位是1,就把這瓶水給第幾個(gè)小白鼠喝。最后大概每個(gè)小白鼠喝500瓶藥水的混合液。如果還不懂,下面列幾個(gè)數(shù)字解釋一下。
瓶子編號(hào) 二進(jìn)制數(shù) 第幾個(gè)小白鼠喝
1 0000000001 1
2 0000000010 2
3 0000000011 1,2
4 0000000100 3
5 0000000101 1,3
大概就是這意思,再反過來,假如1號(hào)和3號(hào)小白鼠死了,死的小白鼠用1表示,再寫成2進(jìn)制數(shù):0000000101,轉(zhuǎn)化為十進(jìn)制數(shù)是5,從上面列出來的也可以看出1,3都喝了5號(hào)瓶的水,所以就是第五瓶水有毒。
解決方案
1)我們將1000瓶液體編號(hào)1~1000,然后將編號(hào)轉(zhuǎn)化為10位二進(jìn)制,如1號(hào)就是0000000001;
2)將十只小白鼠編號(hào)1~10;
3)將液體的二進(jìn)制編號(hào)上為1的位數(shù)給對(duì)應(yīng)的小白鼠喝,如液體編號(hào)為 1111100000,那就是1~5號(hào)小白鼠不喝這瓶液體,6~10號(hào)小白鼠喝這瓶液體;
4)一星期后觀察小白鼠的死亡情況,如果1~5號(hào)小白鼠死亡,6~10號(hào)小白鼠存活,那么有毒的那瓶液體對(duì)應(yīng)的二進(jìn)制編碼為 0000011111;
5)將第四步得到的二進(jìn)制編碼轉(zhuǎn)化為十進(jìn)制,這里是31號(hào),因此我們可以推斷出編號(hào)為31的液體是被污染的。
cookie 和session 的區(qū)別:
cookie和session的共同之處在于:cookie和session都是用來跟蹤瀏覽器用戶身份的會(huì)話方式。
cookie 和session 的區(qū)別:
1、cookie數(shù)據(jù)存放在客戶的瀏覽器上,session數(shù)據(jù)放在服務(wù)器上。
2、cookie不是很安全,別人可以分析存放在本地的COOKIE并進(jìn)行COOKIE欺騙,考慮到安全應(yīng)當(dāng)使用session。
3、session會(huì)在一定時(shí)間內(nèi)保存在服務(wù)器上,超過時(shí)間會(huì)銷毀這個(gè)SESSION。當(dāng)訪問增多,會(huì)比較占用你服務(wù)器的性能考慮到減輕服務(wù)器性能方面,應(yīng)當(dāng)使用COOKIE。
4、單個(gè)cookie保存的數(shù)據(jù)不能超過4K,很多瀏覽器都限制一個(gè)站點(diǎn)最多保存20個(gè)cookie。
5、所以個(gè)人建議:將登陸信息等重要信息存放為SESSION,其他信息如果需要保留,可以放在COOKIE中
還有什么可以問我的嗎
這個(gè)問題一般來說會(huì)有二面,只要不問一些敏感話題就行了。
第二天早上收到二面通知,但是說需要現(xiàn)場面。思考了半天,決定還是去現(xiàn)場面試,雖然需要差不多單程900的車費(fèi),萬一現(xiàn)場面試更簡單呢是吧。當(dāng)然我也知道,我不去一定會(huì)后悔,索性還是去嘗試未嘗不是一件好事,畢竟正好還有小米和滴滴,bigo的現(xiàn)場面試。從南方到北方,郵箱通知上面是九點(diǎn)到西土城的泰富酒店簽到,下火車時(shí)間差不多為六點(diǎn)多,所以到達(dá)那里的時(shí)候差不多七點(diǎn),我是第一個(gè)到那里并簽到的,然后就在那里看自己準(zhǔn)備的算法題,其實(shí)昨天晚上在火車上也復(fù)習(xí)了很久,因?yàn)槲視?huì)盡全力的去完成這次任務(wù),以至今也沒后悔之言。北京的天空依然那么的純藍(lán)!
2 二面(現(xiàn)場面)
我們簽到以后,面試官可以看見簽到時(shí)間,是一哥很溫柔的小哥,讓我把行李放了坐下,別緊張,先自我介紹,然后他說,你這么遠(yuǎn)過來其實(shí)沒必要的,可以申請(qǐng)遠(yuǎn)程的,不然太折騰了,今天我們就簡單問問。
自我介紹
自我介紹完了以后
面試官:你覺得你的一面感覺如何
我:我說一面面試官很好(其實(shí)我從之前的溝通中已經(jīng)感覺一面二面是同一個(gè)面試官了),不太會(huì)的都會(huì)引導(dǎo)我,然后回頭查了相關(guān)的資料。面試官還是比較滿意的。注意:復(fù)盤很重要,一般都有面試記錄的。
我看你寫了三個(gè)項(xiàng)目,說一個(gè)熟悉一些的,背景,你做了啥,有什么難點(diǎn)
面試官:我們看幾個(gè)簡單題
構(gòu)造函數(shù)為什么不能是虛函數(shù)
虛函數(shù)的調(diào)用需要虛函數(shù)表指針,而該指針存放在對(duì)象的內(nèi)容空間中;若構(gòu)造函數(shù)聲明為虛函數(shù),那么由于對(duì)象還未創(chuàng)建,還沒有內(nèi)存空間,更沒有虛函數(shù)表地址用來調(diào)用虛函數(shù)。
Makefile、GDB應(yīng)該都用過吧
可以參考陳皓很多年前寫的一個(gè)專欄,如果沒找到電子版可以私我!
原子變量和volatile區(qū)別(C++11)
Volatile變量可以確保先行關(guān)系,即寫操作會(huì)發(fā)生在后續(xù)的讀操作之前, 但它并不能保證原子性。例如用volatile修飾count變量那么 count++ 操作就不是原子性的。而AtomicInteger類提供的atomic方法可以讓這種操作具有原子性如getAndIncrement()方法會(huì)原子性的進(jìn)行增量操作把當(dāng)前值加一,其它數(shù)據(jù)類型和引用變量也可以進(jìn)行相似操作。
智能指針介紹(C++11)
1.auto_ptr主要是用來解決資源自動(dòng)釋放的問題;auto_ptr支持賦值和復(fù)制,將指針的所有權(quán)轉(zhuǎn)移,但是如果轉(zhuǎn)移后再訪問原來得指針,行為不確定,程序可能會(huì)在運(yùn)行時(shí)出錯(cuò)。
2.unique_ptr與auto_ptr一樣,也是建立所有權(quán)機(jī)制,但是不支持復(fù)制和賦值,所以將一個(gè)unique_ptr對(duì)象賦值給另一個(gè)時(shí),程序編譯出錯(cuò);但如果將臨時(shí)的unique_ptr賦值或復(fù)制給另一個(gè)對(duì)象時(shí),沒有問題。unique_ptr比auto_ptr更安全。
3.shared_ptr和unique_ptr都只能一個(gè)智能指針引用對(duì)象,而shared_ptr則是可以多個(gè)智能指針同時(shí)擁有一個(gè)對(duì)象。shared_ptr實(shí)現(xiàn)方式就是使用引用計(jì)數(shù)。引用計(jì)數(shù)的原理是,多個(gè)智能指針同時(shí)引用一個(gè)對(duì)象,每當(dāng)引用一次,引用計(jì)數(shù)加一,每當(dāng)智能指針銷毀了,引用計(jì)數(shù)就減一,當(dāng)引用計(jì)數(shù)減少到0的時(shí)候就釋放引用的對(duì)象。這種引用計(jì)數(shù)的增減發(fā)生在智能指針的構(gòu)造函數(shù),復(fù)制構(gòu)造函數(shù),賦值操作符,析構(gòu)函數(shù)中。
這種方式使得多個(gè)智能指針同時(shí)對(duì)所引用的對(duì)象有擁有權(quán),同時(shí)在引用計(jì)數(shù)減到0之后也會(huì)自動(dòng)釋放內(nèi)存,也實(shí)現(xiàn)了auto_ptr和unique_ptr的資源釋放的功能。
4.weak_ptr,shared_ptr是一種強(qiáng)引用的關(guān)系,智能指針直接引用對(duì)象。那么這個(gè)會(huì)代碼一個(gè)隱含的問題,就是循環(huán)引用,從而造成內(nèi)存泄漏,首先來看一個(gè)循環(huán)引用的例子。
class Parent
{
public:
shared_ptr<Child> child;
};
class Child
{
public:
shared_ptr<Parent> parent;
};
void Function()
{
shared_ptr<Parent> pA(new Parent);
shared_ptr<Child> pB(new Child);
pA->child = pB;
pB->parent = pA;
}
//第一條語句使得pA引用了Parent一個(gè)指針,Parent引用計(jì)數(shù)為1
//第二條語句使得pB引用了Child一個(gè)指針,Child引用計(jì)數(shù)為1
//第三條語句,調(diào)用了shared_ptr<Child>類的賦值操作符,使得Child引用計(jì)數(shù)變?yōu)?
//第四條語句,調(diào)用了shared_ptr<Parent>類的賦值操作符,使得Parent引用計(jì)數(shù)變?yōu)?/span>
//函數(shù)返回之前調(diào)用了shared_ptr<Parent>和shared_ptr<Child>類的析夠函數(shù),使得Child引用計(jì)數(shù)變?yōu)?,Parent引用計(jì)數(shù)變?yōu)?
咱們看,函數(shù)執(zhí)行完之后new出來的Parent和Child并沒有釋放,所以出現(xiàn)了內(nèi)存泄漏(說出這幾個(gè)字之前,自己應(yīng)該至少知道哪些工具可以檢測內(nèi)存泄漏等相關(guān)問題)。
出現(xiàn)泄漏的原因就是pA和pB相互引用了,導(dǎo)致兩者所引用對(duì)象的引用計(jì)數(shù)不能減少到0,造成泄漏。
如果把第三條語句或者第四條語句任意刪除一個(gè),就不會(huì)有泄漏了。這就是強(qiáng)引用所帶來的問題。weak_ptr從字面意思上可以看出是一個(gè)弱指針,不是說明這個(gè)指針的能力比較弱,而是說他對(duì)他所引用的對(duì)象的所有權(quán)比較弱,說得更直接一點(diǎn)兒就是他并不擁有所引用對(duì)象的所有權(quán),而且他還不能直接使用他所引用的對(duì)象。
在stl中,weak_ptr是和shared_ptr配合使用的,在實(shí)現(xiàn)shared_ptr的時(shí)候也就考慮了weak_ptr的因素。weak_ptr是shared_ptr的觀察者,它不會(huì)干擾shared_ptr所共享對(duì)象的所有權(quán),當(dāng)一個(gè)weak_ptr所觀察的shared_ptr要釋放它的資源時(shí),它會(huì)把相關(guān)的weak_ptr的指針設(shè)置為空,防止weak_ptr持有懸空的指針。注意:weak_ptr并不擁有資源的所有權(quán),所以不能直接使用資源??梢詮囊粋€(gè)weak_ptr構(gòu)造一個(gè)shared_ptr以取得共享資源的所有權(quán)。
weak_ptr是為配合shared_ptr而引入的一種智能指針,它更像是shared_ptr的一個(gè)助手,而不是智能指針,因?yàn)樗痪哂衅胀ㄖ羔樀男袨?,沒有重載operator*和operator->,它的最大作用在于協(xié)助shared_ptr,像旁觀者那樣觀測資源的使用情況。
weak_ptr被設(shè)計(jì)為與shared_ptr共同工作,可以從一個(gè)shared_ptr或者另一個(gè)weak_ptr對(duì)象構(gòu)造,獲得資源的觀測權(quán)。但weak_ptr沒有共享資源,它的構(gòu)造不會(huì)引起指針引用計(jì)數(shù)的增加。同樣,在weak_ptr析構(gòu)時(shí)也不會(huì)導(dǎo)致引用計(jì)數(shù)的減少,它只是一個(gè)靜靜地觀察者。
使用weak_ptr的成員函數(shù)use_count()可以觀測資源的引用計(jì)數(shù),另一個(gè)成員函數(shù)expired()的功能等價(jià)于use_count() == 0,但更快,表示觀測的資源(也就是shared_ptr管理的資源)已經(jīng)不復(fù)存在了。
weak_ptr 沒有重載operator*和->,這是特意的,因?yàn)樗还蚕碇羔?,不能操作資源,這是它弱的原因。但它可以使用一個(gè)非常重要的成員函數(shù)lock()從被觀測的shared_ptr獲得一個(gè)可用的shared_ptr對(duì)象,從而操作資源。當(dāng)expired() == true的時(shí)候,lock()函數(shù)將返回一個(gè)存儲(chǔ)空指針的shared_ptr。
智能指針內(nèi)部實(shí)現(xiàn)(C++11)
智能指針類將一個(gè)計(jì)數(shù)器與類指向的對(duì)象相關(guān)聯(lián),引用計(jì)數(shù)跟蹤該類有多少個(gè)對(duì)象共享同一指針。每次創(chuàng)建類的新對(duì)象時(shí),初始化指針并將引用計(jì)數(shù)置為1;
當(dāng)對(duì)象作為另一對(duì)象的副本而創(chuàng)建時(shí),拷貝構(gòu)造函數(shù)拷貝指針并增加與之相應(yīng)的引用計(jì)數(shù);對(duì)一個(gè)對(duì)象進(jìn)行賦值時(shí),賦值操作符減少左操作數(shù)所指對(duì)象的引用計(jì)數(shù)(如果引用計(jì)數(shù)為減至0,則刪除對(duì)象),并增加右操作數(shù)所指對(duì)象的引用計(jì)數(shù);
調(diào)用析構(gòu)函數(shù)時(shí),構(gòu)造函數(shù)減少引用計(jì)數(shù)(如果引用計(jì)數(shù)減至0,則刪除基礎(chǔ)對(duì)象)。智能指針就是模擬指針動(dòng)作的類。所有的智能指針都會(huì)重載 -> 和 * 操作符。智能指針還有許多其他功能,比較有用的是自動(dòng)銷毀。這主要是利用棧對(duì)象的有限作用域以及臨時(shí)對(duì)象(有限作用域?qū)崿F(xiàn))析構(gòu)函數(shù)釋放內(nèi)存。
DPDK內(nèi)部實(shí)現(xiàn)(這個(gè)是因?yàn)楹啔v上有寫,關(guān)于一個(gè)高性能數(shù)據(jù)包處理庫)
Winpcap:它的一個(gè)流程是npf網(wǎng)絡(luò)組包過濾器首先負(fù)責(zé)從網(wǎng)絡(luò)中采集數(shù)據(jù)包,完成數(shù)據(jù)的過濾拷貝到內(nèi)核緩存區(qū),然后調(diào)用相應(yīng)的動(dòng)態(tài)庫文件將數(shù)據(jù)傳遞到應(yīng)用層緩沖區(qū),最后應(yīng)用程序處理。具體工作原理
(1)網(wǎng)卡接受數(shù)據(jù)包到達(dá)信息,然后產(chǎn)生硬件中斷,通知cpu調(diào)度處理,中斷服務(wù)程序判斷數(shù)據(jù)包的有效性,分配一個(gè)緩沖。
(2)BPF模塊根據(jù)用戶的規(guī)則過濾數(shù)據(jù)包,并把數(shù)據(jù)包插入到內(nèi)核的網(wǎng)卡驅(qū)動(dòng)緩沖隊(duì)列中。
(3)用戶程序通過系統(tǒng)調(diào)用用來讀取內(nèi)核緩沖區(qū)的數(shù)據(jù)包 完成數(shù)據(jù)采集。
優(yōu)化方案
(1)使用雙緩沖減少線程鎖。
(2)多線程。
(3)將原始的數(shù)據(jù)包還原成流保存 減少對(duì)數(shù)據(jù)包的存儲(chǔ),在內(nèi)核層提供了通用socket環(huán)形緩沖,不進(jìn)入內(nèi)核協(xié)議棧,最后在應(yīng)用層通過socket鏈接同時(shí)使用mmap技術(shù)直接訪問socket環(huán)狀緩沖區(qū)
libevent結(jié)構(gòu)、內(nèi)部實(shí)現(xiàn)(回調(diào)+同步)、多線程實(shí)現(xiàn)
首先I/O復(fù)用經(jīng)過封裝;
統(tǒng)一事件源(I/O事件,信號(hào)事件,定時(shí)事件);
事件處理提前注冊(cè)(回調(diào)函數(shù))。
Libevent是線程不安全的,但是libevent提供了鎖機(jī)制,而且在實(shí)現(xiàn)框架上盡量避免使用鎖,像memcache多線程使用libevent,他的實(shí)現(xiàn)現(xiàn)架是主線程監(jiān)聽到讀寫事件分發(fā)任務(wù)(使用CQ隊(duì)列),每個(gè)工作線程對(duì)應(yīng)一個(gè)CQ隊(duì)列。
上面提到的兩個(gè)網(wǎng)絡(luò)庫可以去看看,資料很全的。
epoll內(nèi)部實(shí)現(xiàn)
紅黑樹 就緒事件雙向鏈表;每當(dāng)就緒事件到來時(shí),通過實(shí)現(xiàn)注冊(cè)好的回調(diào)函數(shù)將就緒事件加入到就緒事件隊(duì)列中,epoll_wait返回時(shí)只需要遍歷就緒事件雙向鏈表。
timewait作用
客戶端收到服務(wù)的釋放連接的請(qǐng)求后,不是立馬進(jìn)入CLOSE狀態(tài),而是還要再等待2MSL。理由是:
確保最后一個(gè)確認(rèn)報(bào)文能夠到達(dá)。如果沒能到達(dá),服務(wù)端就會(huì)會(huì)重發(fā)FIN請(qǐng)求釋放連接。等待一段時(shí)間沒有收到重發(fā)就說明服務(wù)的已經(jīng)CLOSE了。如果有重發(fā),則客戶端再發(fā)送一次LAST ack信號(hào)
等待一段時(shí)間是為了讓本連接持續(xù)時(shí)間內(nèi)所產(chǎn)生的所有報(bào)文都從網(wǎng)絡(luò)中消失,使得下一個(gè)新的連接不會(huì)出現(xiàn)舊的連接請(qǐng)求報(bào)文
編程題1 手撕快排
編程題2 二分查找變種
3 總結(jié)
這次面試難度還行,甚至沒有涉及到分布式,微服務(wù),負(fù)載均衡等問題。最終雖然敗北,但是學(xué)會(huì)了一下幾點(diǎn):
公司招你去是干活了,不會(huì)因?yàn)槟阍趺丛趺吹亩档蛯?duì)你的要求標(biāo)準(zhǔn)。
在工具上寫代碼和手撕代碼完全不一樣。
珍惜每一次面試機(jī)會(huì)并學(xué)會(huì)復(fù)盤。
對(duì)于應(yīng)屆生主要考察的還是計(jì)算機(jī)基礎(chǔ)知識(shí)的掌握,項(xiàng)目要求沒有那么高,是自己做的項(xiàng)目就使勁摳細(xì)節(jié),做測試。只有這樣,才知道會(huì)遇到什么問題,遇到什么難點(diǎn),如何解決的。從而可以侃侃而談了。
點(diǎn)【在看】是最大的支持
免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺(tái)僅提供信息存儲(chǔ)服務(wù)。文章僅代表作者個(gè)人觀點(diǎn),不代表本平臺(tái)立場,如有問題,請(qǐng)聯(lián)系我們,謝謝!