2018年3月28日 阿里巴巴電話一面 當天下午4點左右,阿里巴巴從浙江杭州打來的電話:0571-28223456 ,一開始我沒接到,5分鐘后我才發(fā)現(xiàn)這個電話(提醒:手機一定不要靜音,隨時保證能接到電話),當我發(fā)現(xiàn)后就立即打回去,幸運的是,能夠接通,阿里的接線系統(tǒng)還是很智能的,主動提示5分鐘前有打我電話,并且自動轉(zhuǎn)接到那個電話。接通之后我解釋了一下,面試官語氣很和藹,主動提出給我打過來,我表示要花2分鐘拿紙和筆,實際上我還拿了電腦,機智吧!
面試官問的面試題: 接下來就是面試內(nèi)容:
面試主要分為三個部分:基礎知識、項目內(nèi)容和實習經(jīng)歷、應聘崗位相關知識和其他
一:基礎知識
面試官會問你主要熟悉的語言,我是學C++的,然后他就開始問C++相關的知識,我主要問到了:
A: C++的指針和引用的區(qū)別:
指針是一個對象,這個對象里存儲的是它所指向的另一個對象的地址。引用其實是一個對象的別名,引用是必須在初始化時與對象綁定,而且一經(jīng)聲明,就不能再更改綁定到其他對象。
問題引申:
指針定義:值為地址的變量。
指針的運算:兩個基本的運算符:&(取址運算符)和*(間接訪問運算符/解引用指針),除此之外,還有加減算數(shù)運算,關系運算(== 和 !=),以及指針的類型轉(zhuǎn)換:強制類型轉(zhuǎn)換和C++類型轉(zhuǎn)換操作符 static_cast<類型>(表達式) ,注意:void類型指針 void * pVoid 可以從任意類型的指針賦值(強制轉(zhuǎn)換)而來。
指針分類:根據(jù)所指對象類型區(qū)分:int、char、double、class等,還有 nullptr 指針 和 void *指針; 常量指針(指向常量的指針) 和 指針常量(該指針是常量);
常量指針: const int * p ; 特點就是 const 是對 int 的修飾,說明所指對象是一個int 型常量。
指針常量: int * const p ; 特點就是 const 是對 * 的修飾,說明該指針是個常量。
升級問題:迭代器(iterator)和指針(pointer)區(qū)別:STL 容器類的 iterator 迭代器是類模板,它可以遍歷容器內(nèi)的全部或者部分元素,本質(zhì)是封裝了原生指針,提供了
比指針更高級的行為,可以成為智能指針,有++,-- ,->,*等操作,一共分為輸入迭代器(input iterator)、輸出迭代器(output iterator)、前向迭代器(forward iterator)、雙向迭代器(bidirectional iterator)、隨機存取迭代器(random access iterator)。
在范圍上,pointer 屬于 iterator 的一種(random access iterator)
在功能上,iterator 有著比 pointer 更細的劃分并對應能力不同的功能(重載不同的運算符)
在行為上,iterator 比 pointer 更統(tǒng)一和良好的用法(更輕易使用 begin()、end()且不用擔心越界)
B:面向?qū)ο蟮娜齻€基本特征:封裝、繼承、多態(tài)
封裝,也就是把客觀事物封裝成抽象的類,并且類可以把自己的數(shù)據(jù)和方法只讓可信的類或者對象操作,對不可信的進行信息隱藏。
繼承是指這樣一種能力:它可以使用現(xiàn)有類的所有功能,并在無需重新編寫原來的類的情況下對這些功能進行擴展。
多態(tài)性(polymorphisn)是允許你將父對象設置成為和一個或更多的他的子對象相等的技術,賦值之后,父對象就可以根據(jù)當前賦值給它的子對象的特性以不同的方式運作。簡單的說,就是一句話:允許將子類類型的指針賦值給父類類型的指針。
實現(xiàn)多態(tài),有二種方式,覆蓋,重載。覆蓋,是指子類重新定義父類的虛函數(shù)的做法。重載,是指允許存在多個同名函數(shù),而這些函數(shù)的參數(shù)表不同(或許參數(shù)個數(shù)不同,或許參數(shù)類型不同,或許兩者都不同)。其實,重載的概念并不屬于“面向?qū)ο缶幊獭?,重載的實現(xiàn)是:編譯器根據(jù)函數(shù)不同的參數(shù)表,對同名函數(shù)的名稱做修飾,然后這些同名函數(shù)就成了不同的函數(shù)(至少對于編譯器來說是這樣的)。
多態(tài)的作用是什么呢? 封裝可以隱藏實現(xiàn)細節(jié),使得代碼模塊化;繼承可以擴展已存在的代碼模塊(類);它們的目的都是為了——代碼重用。而多態(tài)則是為了實現(xiàn)另一個目的——接口重用!多態(tài)的作用,就是為了類在繼承和派生的時候,保證使用“家譜”中任一類的實例的某一屬性時的正確調(diào)用。
C:C++內(nèi)存管理:存儲內(nèi)容:
靜態(tài)區(qū):保存自動全局變量和static變量(包括static全局和局部變量)。靜態(tài)區(qū)的內(nèi)容在整個程序的生命周期內(nèi)都存在,有編譯器在編譯的時候分配(數(shù)據(jù)段(存儲全局數(shù)據(jù)和靜態(tài)數(shù)據(jù))和代碼段(可執(zhí)行的代碼/只讀常量))。
棧:保存局部變量。棧上的內(nèi)容只在函數(shù)范圍內(nèi)存在,當函數(shù)運行結束的時候,這些內(nèi)容也會自動銷毀。其特點是效率高但是空間大小有限。
堆:由malloc系列函數(shù)或者new操作符分配的內(nèi)存。其生命周期由free和delete決定。在沒有釋放之前一直存在,直到函數(shù)結束。其特點是使用靈活,空間比較大,但容易出錯。
值得注意的一點是:代碼段中存儲的是可執(zhí)行的代碼和只讀常量,很多人看到代碼段就認為里面只有代碼,數(shù)據(jù)段里面才是存儲數(shù)據(jù)的,其實不是這樣的。
內(nèi)存申請和釋放:
malloc和free函數(shù)是一一對應的,如果malloc兩次但是只free一次就會存在內(nèi)存泄漏,如果malloc一次但是free了兩次,就會出錯
我們知道c++是兼容c的,那我們明明已經(jīng)有了malloc和free來進行動態(tài)內(nèi)容的管理,為什么c++還要定義new和delete運算符來動態(tài)管理內(nèi)存。
實際operator new/operator delete 只是malloc和free的一層封裝。
來看一下它們之間的區(qū)別和聯(lián)系:
1.它們都是動態(tài)管理內(nèi)存的入口。
2.malloc/free是c/c++標準庫的函數(shù),new/delete是c++操作符。
3.malloc/free只是動態(tài)分配/釋放內(nèi)存空間。而new/delete出來分配空間還會調(diào)用構造函數(shù)和析構函數(shù)進行初始化與清理。
4.malloc/free需要手動計算類型大小且會返回void*, new/delete可以自己計算類型的大小,返回對應類型的指針。
我們在c++中是允許進行重載的,那我們也可以重載一下new和delete,我在這就不做了(其實new和delete是不能重載的,即使你進行了重載,也只是重載了operator new和operator delete)。
new和delete在內(nèi)存中所做的事
new做的事: 1.調(diào)用operator new分配空間 2.調(diào)用構造函數(shù)初始化空間
delete做的事: 1.調(diào)用析構函數(shù)清理對象 2.調(diào)用operator delete釋放空間
new[N]做的事: 1.調(diào)用operator new分配空間 2.調(diào)用N次構造函數(shù)分別初始化每個對象
delete做的事: 1.調(diào)用N次析構函數(shù)清理對象 2.調(diào)用operator delete釋放空間
用一張圖來解釋:
D:sleep()和wait()這兩個方法的區(qū)別
1、sleep()是讓某個線程暫停運行一段時間,其控制范圍是由當前線程決定,也就是說,在線程里面決定.
2、而wait(),首先,這是由某個確定的對象來調(diào)用的,將這個對象理解成一個傳話的人,當這個人在某個線程里面說"暫停!",也是 thisOBJ.wait(),這里的暫停是阻塞
3、區(qū)別:
sleep()和wait()函數(shù)的區(qū)別:
(1)兩者比較的共同之處是:兩個方法都是使程序等待多少毫秒。
(2)最主要區(qū)別是:sleep()方法沒有釋放鎖。而wait()方法釋放了鎖,使得其他線程可以使用同步控制塊或者方法。
(3)sleep()指線程被調(diào)用時,占著CPU不工作,形象的說明為“占著CPU”睡覺。
sleep(2000)表示:占用CPU,程序休眠2秒。
wait(2000)表示:不占用CPU,程序等待2秒。
引申:掛起和阻塞區(qū)別:
(1)掛起是一種主動行為,因此恢復也應該要主動完成。而阻塞是一種被動行為,是在等待事件或者資源任務的表現(xiàn),你不知道它什么時候被阻塞,也不清楚它什么時候會恢復阻塞。
(2)阻塞(pend)就是任務釋放CPU,其他任務可以運行,一般在等待某種資源或者信號量的時候出現(xiàn)。掛起(suspend)不釋放CPU,如果任務優(yōu)先級高,就永遠輪不到其他任務運行。一般掛起用于程序調(diào)試中的條件中斷,當出現(xiàn)某個條件的情況下掛起,然后進行單步調(diào)試。
程序狀態(tài)變化圖:
E:進程和線程的區(qū)別
進程是cpu資源分配的最小單位,線程是cpu調(diào)度的最小單位。進程是資源的分配單位,線程是CPU在進程內(nèi)切換的單位,線程屬于進程。
接下來是場景問題:
I-面試--超大文件取交集:問題:現(xiàn)有兩個各有20億行的文件,每一行都只有一個數(shù)字,求這兩個文件的交集。
我的回答:1.先將文件進行排序(外存排序),然后對兩個文件中的數(shù)選一個hash函數(shù),能將數(shù)據(jù)集范圍的整數(shù)分到若干個桶中,每個桶中落入的數(shù)的個數(shù)能夠內(nèi)存處理即可 2. 每個桶內(nèi)進行常規(guī)求交集即可
此題牽涉到外存排序:外排序分兩個步驟:預處理和合并排序。先將文件分段;然后利用內(nèi)部排序方法(快排,歸并,堆排序等),將每一段排序成為順串,生成后寫入外存。這樣外存上就得到了m個順串。最后,對這些順串進行歸并,使得其長度逐漸增大,直到所有帶排序的數(shù)字成為一個順串為止。
外部排序最常用的算法是多路歸并排序,即將原文件分解成多個能夠一次性裝入內(nèi)存的部分,分別把每一部分調(diào)入內(nèi)存完成排序。然后,對已經(jīng)排序的子文件進行歸并排序。
第二部分:問的項目相關內(nèi)容和實習內(nèi)容
問:1、項目具體內(nèi)容和分工;2、你負責的部分簡單描述,分析其中的難點和收獲;3、實習的具體工作職責和成效;4、實習收獲到的知識。
第三部分:問測試相關的知識,這塊問得比較淺,比如說平時用什么工具測試