常見問題總結 C++易混淆概念

C++

1. 實現memcpy, strcpyphp

若是目標地址大於源地址,先拷貝高位源地址;
若是目標地址小於源地址,先拷貝低位源地址。
memcpy基本原則
 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 */
mymemcpy

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 }
strcpy(未考慮內存覆蓋)
 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 */
strcpy
 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 }
strncpy
 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 }
strcat
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 }
strcmp

 

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
vector

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
如何釋放掉vector的多餘內存

 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
const的用法

 

拓展: 

4.1 const,volatile,mutable對比

 

5. 講一下智能指針的原理,並實現一個智能指針。

 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: 畫一下有虛函數的狀況下內存佈局大概是什麼樣的?

 ref1    ref2(很詳細!)

 

12. C++ this指針,動態綁定和靜態綁定,空指針調用成員函數

看一下這幾篇文章: ref1     ref2      ref3      ref4      ref5

 

 

 

static關鍵字相關   看一下 ref

靜態成員函數不能夠調用類的非靜態成員,由於靜態成員函數不含this指針。【注意:是的,不是隨便一個非靜態變量】

局部靜態變量的構造是線程安全的。

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

C++零碎知識點彙總

 

其餘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

 =======================================================================================================================

機率題 reference

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

=======================================================================================================================

操做系統  reference

 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實現原理
View Code

 

 

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協議相關

 從輸入 URL 到頁面加載完的過程當中都發生了什麼事情

拓展:參考下這篇文章,很是好。

其餘網絡面試題

 

 

 

 

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名

 

拓展:找前5名呢?   ref2     ref

 

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:  ref1   ref2

=======================================================================================================================

ref: http://www.nowcoder.com/ta/nine-chapter?page=1

相關文章
相關標籤/搜索