1. 程式人生 > >常見的字串面試題

常見的字串面試題

      基本上求職者進行筆試時沒有不考字串的。字串也是一種相對簡單的資料結構,結合指標,容易多次引起面試官反覆發問。我曾不止一次在筆試或面試時遇到下面幾道試題。事實上,字串也是一個考驗程式設計師程式設計規範和程式設計習慣的重要考點。不能忽視這些細節,因為這些細節會體現你在作業系統、軟體工程、邊界記憶體處理等方面的知識掌控能力。

一、整數與字串之間的相互轉換
1.將字串轉換成整數

例如有一字串str[]=“1234”,最直觀的轉換方法就是依次將每一個字元轉換成相應的數字,然後乘10累加,即((1*10+2)*10+3)*10+4。想要得到每一位相應的數字,只需用每個字元減去數字0的ASCII碼,即2= str[1]-'0'。
      如果字串首字元標示的是一個負數,即str[0]=='-'。那麼此時應該設定一個符號判斷標示位(用來判斷以後得到的整數是否需要乘-1),並把要處理的字元陣列下標設定為1。
      int str_to_int(char str[])
      {
        int i=0, isNeg=0,num=0;
        if(str[0]=='-')
          {isNeg=1;
           i=1;
          }
        while(str[i])
          {num=num*10+(str[i]-'0');
           i++;
          }
        if(isNeg)
          num*=-1;
        return num;
      }

2.將整數轉換為字串
      將整數轉換為字串相對要複雜些。通過取模,並結合商與餘數的關係,可以有幾種方法。例如,123除以100,商為1,餘數為23,這樣,首先可以把“1”儲存到字串裡。然後23除以10,商為2,餘數為3。這樣就可以得到字串“123”了。但是,怎樣來確定整數的位數確實比較麻煩。有一種相對簡單的方法。
      首先將123除10取模,得到數字3,此時商為12。再將12除10取模,得到數字2,商為1。這樣,我們可以得到字串“321”,接著進行一次逆序即可得到想要的字串。
    同樣,如果該整數小於0,我們需要人為地將其變成正數,再進行取模運算!!
       char int_to_str(int num,char str[])
       {
        int i=0,j=0,isneg=0;
        char temp[10];
        if(num<0)
          {
           num*=-1;
           isNeg=1;
          }
        do{
           temp[i]=(num%10)+'0';
           num/=10;
           i++;
            }while(num)    //使用do-while結構保證當num為0時也執行迴圈。
        if(isNeg)
          temp[i++]='-';
        while(i>0)
          str[j++]=temp[--i];
        str[j]='/0';      //字串結束符不能忘掉。
       }

二、傳遞動態記憶體
What will happen after running the "Tests"?
    1. #include<iostream>
       void GetMemory(char *p, int num)
        {
          p=(char *)malloc(sizeof(char)*num);
        }
        int main()
        {
         char *str=NULL;
         GetMemory(str,100);
         strcpy(str,"hello");
         return 0;
        }

      程式崩潰。毛病出在函式GetMemory中。該函式中的引數*p實際上是主函式中str的一個副本,編譯器總是要為函式的每個引數做臨時副本。在本程式段中,p申請了新的記憶體,只是把p所指向的記憶體地址改變了,但是str絲毫未變。因為函式GetMemory沒有返回值,因此str並不指向p所申請的那段記憶體,所以函式GetMemory並不輸出任何東西。事實上,每執行一次GetMemory就會申請一塊記憶體,但是申請的記憶體卻不能得到有效地釋放,結果是記憶體一直被佔用,最終造成記憶體洩露。
      修改方法有2種。(1)我們可以用函式的返回值來傳遞動態記憶體,把GetMemory函式的返回型別改為指標型別即可。
        char *GetMemory(char *p, int num)
        {
          p=(char *)malloc(sizeof(char)*num);
          return p;
        }
    (2)如果一定要用指標引數去申請記憶體,那麼應該採用指向指標的指標,傳str的地址給函式GetMemory。
        void GetMemory(char **p, int num)
        {
          *p=(char *)malloc(sizeof(char)*num);
        }
        int main()
        {
         char *str=NULL;
         GetMemory(&str,100);
         strcpy(str,"hello");
         return 0;
        }

    2.#include <iostream>
      using namespace std;
      char *GetMemory(void)
      {
        char p[]="hello";
        return p;
      }
      int main()
      {
        char *str=NULL;
        str=GetMemory();
        cout<<str;
        return 0;
      }
       這段程式碼的錯誤就顯而易見了。因為函式GetMemory返回的是一個指向“棧記憶體”的指標,當呼叫函式結束後,該指標的地址不是NULL,但是原來的內容已經被清楚,新內容不可知。所以,程式輸出的可能是亂碼,也有可能正常輸出。

三、字元指標
What will happen after running the "Tests"?

     #include <iostream>
     using namespace std;
     int main()
      {
        char *str="hello,every one!";
        strcpy(str,"hello,world");
        cout<<str;
      }
       這段程式碼的迷惑性是很強的。程式直接使用字元指標來初始化字串。在C++中,用雙引號括起來的字串被規定為const型別!這樣,意味著str也隱含地被設定為const型別,指向的是全域性的const記憶體區。所以,程式無法通過strcpy試圖修改str字串的內容。