1. 實現memcpy, strcpyphp
若是目標地址大於源地址,先拷貝高位源地址;
若是目標地址小於源地址,先拷貝低位源地址。
1 void mymemcpy(void* dst, const void* src, size_t num) { 2 assert(src != NULL && dst != NULL); 3 const char* psrc = (const char*)src; 4 char* pdst = (char*) dst; 5 if (pdst > psrc && pdst < psrc + num) { 6 psrc = psrc + num - 1; 7 pdst = pdst + num - 1; 8 while (num--) 9 *pdst-- = *psrc--; 10 } 11 } else { 12 while (num--) { 13 *pdst++ = *psrc++; 14 } 15 } 16 } 17 18 /* 19 易錯點: 20 1. 函數接口:用void*比較通用一些;並且,src要加上const。 21 2. 判空是個很重要的考察點!這裏用assert實現; 22 3. 下面對指針從void*轉換到char* 和const char*; 23 4. 若是對size_t進行操做時必定要注意,size_t是unsigned,它降到0以後再減一就變成INT_MAX了,可不是-1! 24 */
follow up:如何優化?html
默認的memcpy是逐字節拷貝; 優化方法是,不用一個字節一個字節的拷貝; 能夠多字節拷貝,或者整塊的拷貝,也能夠是用int指針拷貝(一個int佔4字節)。 若是用int指針拷貝,須要分別計算一下 wordNum = num / 4; slice = num % 4;
拓展:strcpy等一系列經典函數實現 ref ref2 ref3 ref4nginx
除了memcpy外,其餘函數在實現時能夠不用考慮內存覆蓋問題。具體能夠和interviewer溝通。c++
1 char* strcpy(char* dst, const char* src) { 2 assert(dst != NULL && src != NULL); 3 char* pdst = dst; 4 const char* psrc = src; 5 while (*psrc != '\0') { 6 *pdst++ = *psrc++; 7 } 8 *pdst = '\0'; 9 return dst; 10 }
1 char* mystrcpy(char* dst, const char* src) { 2 assert(dst != NULL && src != NULL); 3 int size = strlen(src) + 1; // 4 const char* psrc = src; 5 char* pdst = dst; 6 if (psrc < pdst && psrc + size > pdst) { 7 psrc += size - 1; 8 pdst += size - 1; 9 while (size--) { 10 *pdst-- = *psrc--; 11 } 12 } else { 13 while (size--) { 14 *pdst++ = *psrc++; 15 } 16 } 17 return dst; 18 } 19 20 /* 21 須要注意的是,計算size時應該在strlen(src)基礎上+1,由於要把字符串末尾的'\0'計算進去。 22 有返回值的緣由,是爲了支持鏈式表達式,好比: 23 int iLength=strlen(strcpy(strA,strB)); 24 25 http://www.cnblogs.com/kedebug/archive/2012/12/23/2829945.html 26 */
1 char* mystrncpy(char* dst, const char* src, size_t size) { 2 assert(dst != NULL && src != NULL); 3 char* pdst = dst; 4 const char* psrc = src; 5 size_t i = 0; 6 while (i++ < size && (*pdst++ = *psrc++) != '\0'); 7 if (*pdst != '\0') { 8 *pdst = '\0'; 9 } 10 return dst; 11 }
1 char* strcat(char* dst, const char* src) { 2 assert(dst != NULL && src != NULL); 3 char* pdst = dst; 4 const char* psrc = src; 5 while (*pdst != '\0') { 6 pdst++; 7 } 8 while (*psrc != '\0') { 9 *pdst++ = *psrc++; 10 } 11 *pdst = '\0'; 12 return dst; 13 }
1 int strcmp(const char* str1, const char* str2) { 2 assert(str1 != NULL && str2 != NULL); 3 while (*str1++ == *str2++) { 4 if (*str1 == '\0') { 5 return 0; 6 } 7 } 8 return *str1 - *str2; 9 }
2. STL中vector的實現及原理git
1 // Vector.h 2 3 #ifndef VECTOR_H 4 #define VECTOR_H 5 6 template <typename Object> 7 class Vector 8 { 9 public: 10 explicit Vector(): objects(0), theSize(0),theCapacity(0) {} 11 12 explicit Vector(int initSize) 13 : theSize(initSize), theCapacity(initSize + SPARE_CAPACITY) 14 { 15 objects = new Object[theCapacity]; 16 for(int i=0; i<initSize; ++i) 17 objects[i] = 0; 18 } 19 20 Vector(const Vector & rhs) 21 { operator=(rhs); } 22 23 ~Vector() 24 { delete [] objects; } 25 26 const Vector & operator= (const Vector & rhs) 27 { 28 if(this != &rhs) // check for aliasing 29 { 30 delete [] objects; 31 theSize= rhs.size(); 32 theCapacity = rhs.capacity(); 33 34 objects = new Object[ capacity() ]; 35 for(int k = 0; k < size(); ++k) 36 objects[k] = rhs.objects[k]; 37 } 38 return *this; 39 } 40 41 void resize(int newSize) 42 { 43 if(newSize > theCapacity) 44 reserve(newSize * 2 + 1); 45 theSize = newSize; 46 } 47 48 void reserve(int newCapacity) 49 { 50 if(newCapacity < theSize) 51 return; 52 53 Object * oldArray = objects; 54 55 objects = new Object[ newCapacity ]; 56 for(int k = 0; k < theSize; ++k) 57 objects[k] = oldArray[k]; 58 59 theCapacity = newCapacity; 60 61 delete [] oldArray; 62 } 63 64 Object & operator[] (int index) 65 { 66 return objects[index]; 67 } 68 const Object & operator[] (int index) const 69 { 70 return objects[index]; 71 } 72 73 bool empty() const 74 { 75 return size() == 0; 76 } 77 int size() const 78 { 79 return theSize; 80 } 81 int capacity() const 82 { 83 return theCapacity; 84 } 85 86 void push_back(const Object & x) 87 { 88 if(theSize == theCapacity) 89 reserve(2 * theCapacity + 1); 90 objects[ theSize++ ] = x; 91 } 92 void pop_back() 93 { 94 theSize--; 95 } 96 97 const Object & back() const 98 { 99 return objects[theSize-1]; 100 } 101 102 typedef Object * iterator; 103 typedef const Object * const_iterator; 104 105 iterator begin() 106 { return &objects[0]; } 107 const_iterator begin() const 108 { return &objects[0]; } 109 iterator end() 110 { return &objects[size()]; } 111 const_iterator end() const 112 { return &objects[size()]; } 113 114 enum{ SPARE_CAPACITY = 16 }; 115 private: 116 int theSize; 117 int theCapacity; 118 Object * objects; 119 }; 120 121 #endif
ref1 ref2:Weiss<Data Structure in C++> Ch3.4 ref3github
拓展:面試
2.1 算法
vector已經申請的內存空間並不會縮減,即便調用clear()函數,也只是清空vector的全部元素,真正佔用的內存空間也不會減小。(所以,先在vector裏插入1w個元素再挨個刪去直到剩10個元素,vector佔用的內存空間仍是維持在1w個元素時的狀態。) 解決辦法: vector<int>(nums).swap(nums); 相似地, string(s).swap(s); 原理: 先建立一個臨時拷貝並利用拷貝構造函數對其初始化,值得注意的是,使用拷貝構造函數時其容量是儘量小的符合所需數據的。緊接着將該拷貝與原先的vector v進行交換(swap)。執行交換後,臨時變量會被銷燬,內存獲得釋放。此時的v即爲原先的臨時拷貝,而交換後的臨時拷貝則爲容量很是大的vector(不過已經被銷燬) http://blog.jobbole.com/37700/ 《Effective STL》-Item17 http://www.cnblogs.com/summerRQ/articles/2407974.html
map,set,deque... 編程
3. 實現一個string類緩存
4. const的用法
1. const用於指針時: const在星號左側,則const修飾指針所指向的變量,即指針指向的是常量; const在星號右側,則const修飾指針自己,即指針自己是常量。 可參考ref1的例子。 ref1: http://blog.csdn.net/wen294299195/article/details/6857395 2. const用於函數時: 若const在函數名以後,說明該函數不能修改對象中的數據。若是有特例須要讓該函數修改的話,能夠把類中的那幾個特例成員變量用mutable修飾。ref 若const在函數名以前,則做用於返回值,意味着該函數返回的值只能被讀取,而不能被修改。 參考ref2的例子。 ref2: http://www.iteblog.com/archives/214
拓展:
follow up: 垃圾回收機制。
6. 運算符重載
7. 實現一個單例模式類
follow up: 如何定義只能在堆上生成的對象? 只能在棧上生成的呢?
8. struct對齊問題
對齊規則:
1)在沒有#pragma pack(n)的狀況下,struct內各個成員的對齊係數爲本身的長度。
2)在有#pragma pack(n)的狀況下,struct內各個成員的對齊係數爲 min(n, 本身的長度) .
3)struct總體的對齊係數爲struct內各成員對齊係數的最大值。
4)struct內每一個成員相對於struct首地址的offset都是該成員自身對齊係數的整數倍(不然要補全);並且,struct總體也要保證佔用的總大小是struct總體對齊係數的整數倍(末尾不夠要補全)。
9. C++易混淆概念
10. C++虛函數原理及虛繼承
11. C++對象內存模型
Q: 畫一下有虛函數的狀況下內存佈局大概是什麼樣的?
12. C++ this指針,動態綁定和靜態綁定,空指針調用成員函數
看一下這幾篇文章: ref1 ref2 ref3 ref4 ref5
static關鍵字相關 看一下 ref
靜態成員函數不能夠調用類的非靜態成員,由於靜態成員函數不含this指針。【注意:是類的,不是隨便一個非靜態變量】
局部靜態變量的構造是線程安全的。
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
其餘C++常見問題:
何海濤總結5篇C++面試題: ref1 ref2 ref3 ref4 ref5
http://wenku.baidu.com/view/ad50b2d765ce05087632138c.html
http://blog.csdn.net/worldwindjp/article/details/18909079
http://www.cnblogs.com/wuchanming/p/4367398.html
http://blog.csdn.net/chhuach2005/article/details/40322895
=======================================================================================================================
1. 給N張撲克牌和一個隨機函數,設計一個洗牌算法
2. 如何等機率地從n個數中隨機抽出m個數?
follow up: 若是上題中n大小不肯定,如何作?
3. 給定一個可以生成0,1兩個數的等機率隨機數生成器」,如何生成⼀個產生0,1,2,3的等機率隨機數生成器?
3.1 如何用rand7生成rand9?
3.2 有1枚硬幣,以p的機率產生正面,以1-p的機率產生背面,如何利用它產生一個0.5機率的生成器?
4. A,B,C三人輪流扔硬幣,第一個扔到正面的人算贏,問三我的贏的機率分別爲多大?
5. A有n個硬幣,B有n+1個硬幣,誰丟的正面多誰贏,問A不輸的機率?
6. 一個機器人在原點,右邊有一個距離爲k的點,機器人以p的機率右移一步,1-p機率左移一步, 問通過M步機器人處於k點的機率?
7. 扔硬幣直到連續兩次出現正面,求扔的指望次數
ref1裏面有一些機率題總結的不錯。
ref1: http://noalgo.info/414.html
=======================================================================================================================
1 1. Linux中線程互斥/同步有哪幾種方式? 2 3 2. 一樣能夠實現互斥,互斥鎖和信號量有什麼區別? 4 5 3. 請用普通的互斥鎖編程實現一個讀寫鎖 6 7 4. 編程產生三個線程ABC,並讓它們順次打印ABC 8 9 5. 死鎖是怎麼產生的?如何避免? 10 11 6. Linux中進程通訊有哪些方式? 12 13 7. Linux中進程空間佈局 14 15 8. Linux內存分配原理 16 17 9. malloc函數實現原理 18 19 10. 使用mmap讀寫文件爲何比普通讀寫函數要快? 20 21 11. 靜態連接庫、動態連接庫原理 22 23 12. Linux中signal實現原理
Linux經常使用命令/知識: ref
1. 進程和線程有什麼區別和聯繫
2. 內存管理
夥伴系統
進程間通訊
實現malloc/ malloc原理 ref1 ref2 ref3
鍵盤上敲擊一下鍵/按一下鼠標,後面都有哪些操做?
緩存,LRU算法,進程、線程的概念。
進程調度算法、文件系統。
=======================================================================================================================
1. 100億個整數,如何找到中位數
內存足夠的狀況: 可使用相似quick sort的思想進行[QuickSelection算法],均攤複雜度爲O(n),算法思想以下:
• 隨機選取一個元素,將比它小的元素放在它左邊,比它大的元素放在右邊
• 若是它剛好在中位數的位置,那麼它就是中位數,能夠直接返回
• 若是小於它的數超過一半,那麼中位數必定在左半邊,遞歸到左邊處理
• 不然,中位數必定在右半邊,根據左半邊的元素個數計算出中位數是右半邊的第幾大,而後遞歸到右半邊處理
內存不足的狀況:
方法一:二分法
思路:一個重要的線索是,這些數都是整數。整數就有範圍了,32位系統中就是[-2^32, 2^32- 1], 有了範圍咱們就能夠對這個範圍進行二分,而後找有多少個數小於Mid,多少數大於mid,而後遞歸,和基於quicksort思想的第k大方法相似【即QuickSelection算法】
方法二:分桶法
思路:化大爲小,把全部數劃分到各個小區間,把每一個數映射到對應的區間裏,對每一個區間中數的個數進行計數,數一遍各個區間,看看中位數落在哪一個區間,若夠小,使用基於內存的算法,不然繼續劃分。
=======================================================================================================================
TCP/IP協議相關
TCP和UDP的區別? ref
三次握手,四次揮手 ref
爲何創建鏈接是三次握手,而關閉鏈接倒是四次揮手呢?
由於tcp是全雙工模式,當收到對方的FIN報文時,僅僅表示對方再也不發送數據了可是還能接收數據,可是己方的數據可能尚未發完,有可能在發送對FIN的ACK後再發送一會數據,而後才發FIN。因此己方能夠當即close,也能夠發送一些數據給對方後,再發送FIN報文給對方來表示贊成如今關閉鏈接,所以,己方ACK和FIN通常都會分開發送。
關於tcp中time_wait狀態的4個問題: ref ref2 ref3 ref4
http協議相關
拓展:參考下這篇文章,很是好。
其餘網絡面試題
http://www.nowcoder.com/discuss/1937?type=&order=0&pos=6&page=1?from=wb 【這個總結很是好!認真看一下!】
http://www.cnblogs.com/obama/p/3292335.html
IO複用 summarize
epoll水平觸發,邊緣觸發
select與epoll
用戶態與內核態,以及如何切換
ref0: 這個博主寫的一系列網絡編程文章都特別好(條件變量,epoll)。多看一下
reference 這篇文章對網絡編程的知識點總結的很是好!認真學習一下。
epoll面試相關
http://blog.csdn.net/tom555cat/article/details/24870469
http://www.cppblog.com/peakflys/archive/2012/08/26/188344.html
http://blog.csdn.net/lianxiang_biancheng/article/details/9025881 【看一下這篇裏面epoll源碼,讓人快速理解epoll流程】
nginx入門 reference
=======================================================================================================================
1. 25匹馬,5個跑道,最少比多少次能找到前3名
2.
=======================================================================================================================
1.常見排序算法複雜度、穩定性
選擇排序是每次遍歷一遍剩餘元素,從中選出最小的與前面已排好序的元素的下一位置進行swap。最優狀況下複雜度是O(n^2), 平均和最壞複雜度也是O(n^2)。
冒泡和插入排序的最優複雜度是O(n), 平均和最壞都是O(n^2)。
歸併排序和堆排序的最優、平均、最壞複雜度都是O(nlgn)。
快速排序最壞狀況下是O(n^2), 平均和最優都是O(nlgn).空間複雜度是O(lgN)(由於須要每次記錄pivot的位置)。
穩定性:
不穩定:快速排序、堆排序、選擇排序、希爾排序
穩定:歸併排序、基數排序、冒泡排序、插入排序。
希爾排序是按照不一樣步長對元素進行插入排序。
=======================================================================================================================
ref: http://www.nowcoder.com/ta/nine-chapter?page=1