程序員面試筆試寶典學習記錄(一)(常見面試筆試題目)


摘選著名的互聯網企業的面試筆試真題:

1.extern的作用

自己理解:應該需要區分extern在C語言中和C++語言中的作用,C語言中extern聲明的函數和變量可以被該文件外部模塊引用,C++語言中除了該作用還可以聲明extern “C”聲明一段代碼編譯連接的方法為C語言的方法。

參考:其實extern的百度詞條解釋的很清楚,具體的也是跟我上面自己理解差別不是很大。

(a) extern是C/C++語言中聲明函數和全局變量作用范圍(可見性)的關鍵字,該關鍵字告訴編譯器,其聲明的函數和變量在本模塊或其他模塊中使用(通常,在模塊的頭文件中對本模塊提供給其它模塊引用的函數和全局變量以關鍵字extern聲明。)

(b) 被extern “C”修飾的變量和函數是按照C語言的方式編譯和鏈接的。(C語言不支持函數重載,所以函數的C++和C的編譯方式不同,這一句的作用就是實現C++和C及其他語言混合編程)

2.strstr()函數的作用

strstr()函數的原型一般為extern char * strstr(const char *src , const char *dest) , 其作用就是尋找目標字符串在源字符串中第一次出現的位置。

3.windows線程優先級問題( 進程和線程的區別和聯系 )

我覺得這個概念可能面試、筆試的時候不是很適合,畢竟平台相關,大多數公司可能更多的傾向於linux開發,這個問題更換為進程和線程的區別更好,這個是筆試,面試常見的知識考查。

(a) 通常一個進程可以包含若干個線程,它們可以利用進程所擁有的資源。進程是系統進行資源分配和調度的一個獨立單位,線程是進程的一個實體,是CPU調度和分派的基本單位,它是比進程更小的能獨立運行的基本單位。線程自己基本不擁有系統資源,只擁有一些在運行中必不可少的資源(如程序計數器,一組寄存器和棧),線程可與同屬於一個進程的其他線程共享進程所擁有的全部資源。

線程和進程區別歸納:

  •     地址空間和其他資源:進程間互相獨立,同一個進程的各線程共享。
  •     通信:進程間通信IPC,線程間可以直接讀寫進程序數據段(如全局變量)來進行通信-需要進行同步和互斥的輔助。
  •     調度和切換:線程上下文切換比進程上下文切換快速,高效。
  •     多線程的OS中,進程不是一個可執行的實體。

4.多方法交換x與y的值

5.指針的自加與引用

6.前置++與后置++

前置++和后置++我覺得一個比較重要的問題是C++中重載兩個操作符的時候如何區別:區分前置和后置 函數的參數有一個 (函數重載),后置++有一個(int)參數。

7.inline的作用

inline函數不像正常函數在調用時存在壓棧和call的操作,它會把程序代碼直接嵌入到調用代碼段中,也就是說使用inline函數會增大二進制程序的體積,但是會使執行速度加快。

同時,編譯期間可以對參數進行強類型的檢查,這是inline優於宏的一個方面。

8.二維數組的表示

9.ifndef的作用

條件編譯的語法,一般情況下,源程序中所有的行都參加編譯。但是有時希望對其中一部分內容只在滿足一定條件才進行編譯,也就是對一部分內容指定編譯的條件,這就是“條件編譯”。有時,希望當滿足某條件時對一組語句進行編譯,而當條件不滿足時則編譯另一組語句。

10.KMP算法

字符串匹配的高級算法

11.函數調用方式

  • __cdecl               堆棧由調用者清除          參數從右至左的順序壓入堆棧內
  • __stdcall             堆棧由被調用者清除       參數從右至左的順序壓入堆棧內
  • __fastcall            堆棧由被調用者清除       部分參數保存在寄存器中,然后其他的壓入堆棧內
  • thiscall(非關鍵字)  堆棧由被調用者清除       參數壓入堆棧內,this指針保存在ECX寄存器內

12.重載函數

    函數重載是指在同一作用域內,可以有一組具有相同函數名,不同參數列表的函數,這組函數被稱為重載函數。不能利用返回類型進行重載!類中函數const和非const可以進行重載,其實原理是利用this指針的類型是const和非const進行重載,其實原理就是參數類型不同,const指針orconst引用調用的為const版本的函數~更多函數重載的知識

13.構造函數和析構函數

    虛擬析構函數的使用場景是指向父類的指針實則為子類指針,調用delete的時候使用虛擬析構函數,防止部分內存泄露。

    構造函數不能聲明為虛擬函數,因為對象的虛擬函數表的指針其實是在構造函數內編譯器添加完成的代碼,所以在構造函數執行之前無法訪問到虛擬函數表的。

14.合並兩個有序鏈表

    類似歸並排序,兩個指針歸並即可。

15.100億條記錄的文本文件,取出重復數最多的前10條

    類似top k算法,無法全部讀入內存的top k算法是利用容量為k的最大堆,達到線性時間的top k算法。

    首先利用hash table預處理每個元素出現的次數,然后利用次數執行top k算法。

16.設計一個雙向鏈表,並且提供一個可根據值刪除元素的函數

    STL中的list底層及為雙鏈表實現。

17.二叉樹的多種遍歷算法實現

18.有讀和寫的兩個線程和一個隊列,讀線程從隊列中讀數據,寫線程往隊列中寫數據

    生產者和消費者模型:

    使用信號燈和互斥量。

semaphore mutex = 1;
semaphore fillCount = 0;
semaphore emptyCount = BUFFER_SIZE;

procedure producer() {
    while(true) {
        item = produceItem();
        down(emptyCount);
            down(mutex);
                putItemIntoBuffer(item);
            up(mutex);
        up(fillCount);
    }
}
procedure consumer() {
    while(true) {
        down(fillCount);
            down(mutex);
                item = removeItemFromBuffer();
            up(mutex);
        up(emptyCount);
        consumeItem(item);
    }
}

  不使用信號燈和互斥量。

volatile unsigned int produceCount, consumeCount;
TokenType buffer[BUFFER_SIZE];
 
void producer(void) {
    while (1) {
        while (produceCount - consumeCount == BUFFER_SIZE)
            sched_yield(); // 緩沖區滿
 
        buffer[produceCount % BUFFER_SIZE] = produceToken();
        produceCount += 1;
    }
}
 
void consumer(void) {
    while (1) {
        while (produceCount - consumeCount == 0)
           sched_yield(); // 緩沖區空
 
        consumeToken( buffer[consumeCount % BUFFER_SIZE]);
        consumeCount += 1;
    }
}

19.stack,heap,memory-pool

     

20.TCP的流量控制和擁塞控制機制

     TCP的流量控制就是讓發送方的發送速率不要太快,讓接收方來得及接收。利用滑動窗口機制可以很方便的在TCP連接上實現對發送方的流量控制。TCP的窗口單位是字節,不是報文段,發送方的發送窗口不能超過接收方給出的接收窗口的數值。

    所謂的擁塞控制為防止過多的數據注入到網絡中,這樣可以使網絡中的路由器或鏈路不致過載。擁塞控制索要做的都有一個前提,就是網絡能承受現有的網絡負荷。流量控制往往指點對點通信量的控制,是一個端到端的問題。因特網建議標准RFC2581定義了進行擁塞控制的四種算法,即慢開始(Slow-start),擁塞避免(Congestion Avoidance)快重傳(Fast Restrangsmit)和快回復(Fast Recovery)。

21.寫一個函數,返回一個字符串中只出現一次的第一個字符

     目前想到的方法就是利用hash表記錄每個字符出現的次數,然后兩次遍歷即可找到只出現一次的第一個字符。

22.求一個數組中第k大的數的位置

     

23.面向對象繼承,多態問題,如多態的實現機制

    虛擬函數,指針and引用

24.內聯函數什么時候不展開

     在內聯函數內不允許用循環語句和開關語句。 如果內聯函數有這些語句,則編譯將該函數視同普通函數那樣產生函數調用代碼,遞歸函數(自己調用自己的函數)是不能被用來做內聯函數的。內聯函數只適合於只有1~5行的小函數。對一個含有許多語句的大函數,函數調用和返回的開銷相對來說微不足道,所以也沒有必要用內聯函數實現。

25.成員函數初始化列表有什么作用?什么必須在成員初始化列表中進行初始化?

    類的static變量在類的構造函數前已進行初始化!

    類對象的構造順序:

    (a)分配內存,調用構造函數時,隱式/顯式的初始化各數據成員(順序和類中聲明對象一致)。如果無成員初始化列表。隱式初始化階段按照聲明的順序依次調用所有基類的缺省構造函數,然后所有成員類對象的缺省構造函數。

    (b)進入構造函數執行函數體內語句,函數體內的數據成員的設置被認為賦值,而不是初始化。

    所以,使用初始化列表的兩個情況:

    1)必須使用初始化列表進行初始化![1]數據成員為類對象並且該類對象僅提供帶參數的構造函數[2]const修飾的數據成員[3]引用數據成員;

    2)考慮效率的時候!因為未利用初始化列表而是在構造函數體內進行賦值,則調用了缺省構造函數和賦值運算符操作。如果數據成員為自定義的類對象,則效率比直接利用構造函數初始化低很多。

27.指針與引用的區別

    相同點:

  •     都是地址的概念;指針指向一塊內存,它的內容是所指內存的地址;而引用則是某塊內存的別名。

    不同點:

  •     指針是一個實體,而引用僅是個別名
  •     引用只能並且必須在定義時被初始化一次,之后不可變(類似常量指針,引用自帶常量指針屬性);指針可變;
  •     引用沒有const,指針有const,const的指針不能夠改變;(int & const refer 不存在,因為引用本身就初始化一次不可變,但是const int &refer是存在的,指引用所指向的值不可改變)
  •     引用不能為空,指針可以為空
  •     sizeof針對指針得到的是指針的大小,針對引用得到的是指向對象的大小;
  •     指針的++操作和引用的++操作完全不同,指針為移動指針地址,引用++操作作用於指向的對象;
  •     引用是類型安全的,而指針不是類型安全的。

28.創建空類時,哪些成員函數是系統默認的?

    構造函數,拷貝構造,賦值函數,析構函數,取址運算符,const取址運算符

29.有10W個IP段,這些IP段之間都不重合,隨便給定一個IP,求出屬於哪個IP段

 

30.網絡編程(網絡編程范式,非阻塞connect)

     常見的IO模型有阻塞、非阻塞、IO多路復用、異步。

31.TCP/IP

 

32.LINUX的命令,原理及底層實現

 

33.LINUX編程,包括所有互斥的方法,多線程編程,進程間的通信

 

34.一個一維數軸上的不同線段,求重復最長的兩個線段

 

35.有向帶權圖最短路徑

 

36.內存溢出和內存泄露有什么區別?

  • 內存溢出 out of memory,是指程序在申請內存時,沒有足夠的內存空間供其使用,出現out of memory;比如申請了一個integer,但給它存了long才能存下的數,那就是內存溢出。
  • 內存泄露 memory leak,是指程序在申請內存后,無法釋放已申請的內存空間,一次內存泄露危害可以忽略,但內存泄露堆積后果很嚴重,無論多少內存,遲早會被占光。

37.利用互斥量和條件變量設計一個消息隊列,具有以下功能:1)創建消息隊列(消息中所含的元素);2)消息隊列中插入消息;3)取出一個消息(阻塞方式);4)取出第一個消息(非阻塞方式)。注意互斥量,條件變量和隊列系統提供

 

38.非遞歸方法實現二叉樹的遍歷

    利用棧stack的方法和morris遍歷方法,分別O(lgn)和O(1)的額外空間。

39.cnwap和cnnet的區別

    CMWAP 和 CMNET 只是中國移動人為划分的兩個GPRS接入方式。前者是為手機WAP上網而設立的,后者則主要是為PC、筆記本電腦、PDA等利用GPRS上網服務。它們在實現方式上並沒有任何差別,但因為定位不同,所以和CMNET相比,CMWAP便有了部分限制,資費上也存在差別。

40.設計一個內存管理策略,要求可以保證多線程安全,防止內存越界等,效率不低於malloc()/free()函數

    

41.排列組合問題

    排列遞歸dfs版本窮舉,另外還可以有一些帶剪枝的題目。

42.若有序的關鍵字序列為{b,c,d,e,f,g,q,r,s,t},則在二分查找關鍵字b的過程中,先后進行比較的關鍵字依次是什么?

    此問題向上取整和向下取整也相關,而且與結束條件相關。

    [0,9]->4(f)

    [0,3]->1(c)

    [0,0]->0(b)

    如果是向下取整則為以上比較過程,依次f,c,b。

43.有一個虛擬存儲系統,若進程在內存中占3頁(初始狀態為空),若采用先進先出頁面淘汰算法,當執行如下訪問下列后,1,2,3,4,5,1,2,5,1,2,3,4,5, 會發生多少缺頁?

     另外一個比較重要的淘汰算法LRU,最近最久未使用。

    3+8 = 11

44.有一個順序棧S,元素s1,s2,s3,s4,s5,s6,依次進棧,如果6個元素出棧順序s2,s3,s4,s6,s5,s1,則順序棧的容量至少應該有多少?

   s1進入,1,s2進入,2,s2彈出,s3進入,2,s3彈出,s4進入,2,s4彈出,s5進入,2,s6進入,3,s6彈出,s5彈出,s1彈出。

   根據以上過程所以順序棧的容量至少為3才可以。

45.[0,2,1,4,3,9,5,8,6,7]是以數組形式存儲的最小堆,刪除堆頂元素0后的結果是多少?

    自己理解:[1,2,5,4,3,9,7,8,6,0]

46.某頁式存儲管理系統中,地址寄存器長度為24位,其中號占14位,則主存的分塊大小是多少字節?

    頁式存儲管理是把主存儲器分成大小相等的許多區,每個區稱為一塊,與此對應,編制程序的邏輯地址也分成頁,頁的大小與塊的大小相等。

    (a) 地址轉換:絕對地址 = 塊號 * 塊長 +塊內地址

    塊號是頁號根據頁表查詢得到

    這里寄存器長度24位,號占14位,所以頁面大小占10位,所以塊的大小也為10位。

47.運算符重載

48.各種排序算法的使用與比較

49.一維數組默認初始化問題

  • 如果不對數組進行任何初始化操作, 僅定義一個數組, 那么數組中這些元素的值是不確定的, 是系統中隨機的一個值。

50.const char *p1 = "hello";char *const p2 = "hello",有什么區別。

const在指針和引用聲明中位置的不同分別代表不同的意義。

  • const char *p1 等價於 char const *p1為指針指向內容為常量,指向字符串常量的指針;
  • char *const p2 為常量指針,指向字符串的常量指針。

51.struct與class有什么區別和聯系

struct與class在C++中看起來沒什么區別,只是使用習慣,不過說到區別可能還有2點吧。

(a)默認的訪問控制,struct默認訪問控制public,class默認訪問控制private,寫代碼時最好標明確訪問控制。

(b)class這個關鍵字還用於定義模板參數,like "typename"。關鍵字struct不能用於定義模板參數。

52.函數指針和指針函數

函數指針:char (*p)();p為指向函數的指針

指針函數:char *p();返回指針的函數

53.指針數組和數組指針

指針數組:char *cp_array[];

數組指針:char (*p_array)[];

54.大端小端

  • 大端模式,是指數據的高位,保存在內存的低地址中,而數據的低位,保存在內存的高地址中,這樣的存儲模式有點兒類似於把數據當作字符串順序處理:地址由小向大增加,而數據從高位往低位放;
  • 小端模式,是指數據的高位保存在內存的高地址中,而數 據的低位保存在內存的低地址中,這種存儲模式將地址的高低和數據位權有效地結合起來,高地址部分權值高,低地址部分權值低,和我們的邏輯方法一致。
static union { char c[4]; unsigned long l; } endian_test = { { 'l', '?', '?', 'b' } };
#define ENDIANNESS ((char)endian_test.l)
//(如果ENDIANNESS=’l’表示系統為little endian,為’b’表示big endian )。

  利用union共享存儲單元的原理。

55.虛函數問題

針對每個類存在一個虛擬函數表,每個類的實例中存在一個指向虛擬函數表的指針。

56.如果判斷單鏈表是否有環

快慢指針,相遇則存在環。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM