1. 程式人生 > >有點意思的C/C++問題及解答:11-15

有點意思的C/C++問題及解答:11-15

問題11:下面這個函式希望完成什麼任務?

[cpp]  view plain copy print ?
  1. int func(int x)   
  2. {   
  3.     int countx = 0;   
  4.     while
    (x)   
  5.     {   
  6.         countx ++;   
  7.         x = x&(x-1);   
  8.     }   
  9.     return countx;   
  10. }   

解答:這個函式是求一個整數的二進位制表示中含1的個數。假定x = 9999,該函式返回8。這是道微軟的面試題,在《程式設計之美》一書中給出了若干種方法,用來求二進位制數中1的個數。

問題12:以下三條輸出語句分別輸出什麼?

[cpp]  view plain copy print ?
  1. char
     str1[] = "abc";   
  2. char str2[] = "abc";   
  3. const char str3[] = "abc";   
  4. const char str4[] = "abc";   
  5. const char* str5 = "abc";   
  6. const char* str6 = "abc";   
  7. cout << boolalpha << ( str1==str2 ) << endl; // 輸出什麼  
  8. cout << boolalpha << ( str3==str4 ) << endl; // 輸出什麼  
  9. cout << boolalpha << ( str5==str6 ) << endl; // 輸出什麼   
解答:輸出分別為false false true。str1 和str2 都是字元陣列,每個都有其自己的儲存區,它們的值則是各 儲存區首地址,不等;str3 和str4 同上,只是按const 語義,它們所指向的資料區不能修改。str5 和str6 並非陣列而是字元指標,並不分配儲存區,其後的“abc”以常量形式存於靜態資料區,而它們自己僅是指向該區首地址的指標,相等。 如果去掉定義str5、str6時加的const修飾,輸出還是相等的。

問題13: 已知String類定義如下,請實現這些函式。

[cpp]  view plain copy print ?
  1. class String   
  2. {   
  3. public:   
  4.     String(const char *str = NULL); //預設建構函式   
  5.     String(const String &another);  //拷貝建構函式   
  6.     ~String();                      //解構函式   
  7.     String & operator =(const String &rhs); //賦值操作符   
  8. private:   
  9.     char *m_data;                   //用於儲存字串   
  10. };   

解答:實現中有幾點要注意:(1)預設建構函式中,判斷str是否為空。(2)解構函式中應使用delete [ ] 運算子。(3)賦值操作符應判斷是否是給自身賦值。程式碼如下:

[cpp]  view plain copy print ?
  1. String::String(const char *str)  
  2. {  
  3.     if(str == NULL)  
  4.     {  
  5.         m_data = new char[1];  
  6.         m_data[0] = '\0';  
  7.     }  
  8.     else  
  9.     {  
  10.         m_data = new char[strlen(str) + 1]; //需要加1,strlen返回的字串長度並不包含'\0'  
  11.         strcpy(m_data,str);  
  12.     }  
  13. }  
  14. String::String(const String &another)  
  15. {  
  16.     m_data = new char[strlen(another.m_data) + 1];  
  17.     strcpy(m_data,another.m_data);  
  18. }  
  19. String& String::operator=(const String &rhs)  
  20. {  
  21.     if(this != &rhs) //防止給自身賦值  
  22.     {  
  23.         delete [] m_data;  
  24.         m_data = new char[strlen(rhs.m_data) + 1];  
  25.         strcpy(m_data,rhs.m_data);  
  26.     }  
  27.     return *this;  
  28. }  
  29. String::~String()  
  30. {  
  31.     delete [] m_data; //注意是delete []  
  32. }  
問題14:寫一個在一個字串(T)中尋找一個子串(P)第一個位置的函式。

解答:用KMP演算法即可。基本策略是預處理子串 P ,獲得其中與模式匹配有關的子字串關係規律,從而當發生匹配失敗時,可以確定繼續與 T 當前位置匹配的 P 的新位置,這樣就不需要在 T 中回溯了。時間複雜度為O(T+P)。

[cpp]  view plain copy print ?
  1. int KMP(char *T, char *P)  
  2. {  
  3.     int lenT = strlen(T);  
  4.     int lenP = strlen(P);  
  5.     int i = 0, j = 0;  
  6.     int *next = new int[lenP + 1];  //最後一個元素用不到  
  7.     Fail(next, P);                  //計算失敗函式  
  8.     while(i < lenT && j < lenP)  
  9.     {  
  10.         if(j == -1 || T[i] == P[j])  
  11.         {  
  12.             i++; j++;  
  13.         }  
  14.         else  
  15.             j = next[j];   //P的下一個比較位置  
  16.     }  
  17.     delete [] next;  
  18.     if(j < lenP || j == 0)  
  19.         return -1;  
  20.     else   
  21.         return i - lenP;  
  22. }  
  23.   
  24. //仍是一個模式匹配的過程,只不過目標串和模式串是同一串P,所以兩個程式碼的程式很相似  
  25. void Fail(int *next, char *P)  
  26. {  
  27.     int lenP = strlen(P);  
  28.     int i = -1,j = 0;  
  29.     next[0] = -1;  
  30.     while(j < lenP)  
  31.     {  
  32.         if(i == -1 || P[i] == P[j])  
  33.         {  
  34.             i++; j++;  
  35.             next[j] = i;  
  36.         }  
  37.         else  
  38.             i = next[i];  
  39.     }  
  40. }  
問題15:為什麼一個空類的sizeof為1而不是0?

解答:空類同樣可以被例項化,每個例項在記憶體中都有一個獨一無二的地址,為了達到這個目的,編譯器往往會給一個空類隱含的加一個位元組,這樣空類在例項化後在記憶體得到了獨一無二的地址。