<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    隨筆-144  評論-80  文章-1  trackbacks-0
    C/C++ 程序設計員應聘常見面試試題深入剖析
    時間:2006-5-30 17:06:00 ?
    .引言

      本文的寫作目的并不在于提供C/C++程序員求職面試指導,而旨在從技術上分析面試題的內涵。文中的大多數面試題來自各大論壇,部分試題解答也參考了網友的意見。

      許多面試題看似簡單,卻需要深厚的基本功才能給出完美的解答。企業要求面試者寫一個最簡單的strcpy函數都可看出面試者在技術上究竟達到了怎樣的程度,我們能真正寫好一個strcpy函數嗎?我們都覺得自己能,可是我們寫出的strcpy很可能只能拿到10分中的2分。讀者可從本文看到strcpy 函數從2分到10分解答的例子,看看自己屬于什么樣的層次。此外,還有一些面試題考查面試者敏捷的思維能力。

      分析這些面試題,本身包含很強的趣味性;而作為一名研發人員,通過對這些面試題的深入剖析則可進一步增強自身的內功。

      2.找錯題

      試題1:

    void test1()
    {
     char string[10];
     char* str1 = "0123456789";
     strcpy( string, str1 );
    }

      試題2:

    void test2()
    {
     char string[10], str1[10];
     int i;
     for(i=0; i<10; i++)
     {
      str1[i] = 'a';
     }
     strcpy( string, str1 );
    }

      試題3:

    void test3(char* str1)
    {
     char string[10];
     if( strlen( str1 ) <= 10 )
     {
      strcpy( string, str1 );
     }
    }

      解答:

      試題1字符串str1需要11個字節才能存放下(包括末尾的’\0’),而string只有10個字節的空間,strcpy會導致數組越界;

      對試題2,如果面試者指出字符數組str1不能在數組內結束可以給3分;如果面試者指出strcpy(string, str1)調用使得從str1內存起復制到string內存起所復制的字節數具有不確定性可以給7分,在此基礎上指出庫函數strcpy工作方式的給10 分;

      對試題3,if(strlen(str1) <= 10)應改為if(strlen(str1) < 10),因為strlen的結果未統計’\0’所占用的1個字節。

      剖析:

      考查對基本功的掌握:

      (1)字符串以’\0’結尾;

      (2)對數組越界把握的敏感度;

      (3)庫函數strcpy的工作方式,如果編寫一個標準strcpy函數的總分值為10,下面給出幾個不同得分的答案:

      2分

    void strcpy( char *strDest, char *strSrc )
    {
      while( (*strDest++ = * strSrc++) != ‘\0’ );
    }

      4分

    void strcpy( char *strDest, const char *strSrc )
    //將源字符串加const,表明其為輸入參數,加2分
    {
      while( (*strDest++ = * strSrc++) != ‘\0’ );
    }

      7分

    void strcpy(char *strDest, const char *strSrc)
    {
     //對源地址和目的地址加非0斷言,加3分
     assert( (strDest != NULL) && (strSrc != NULL) );
     while( (*strDest++ = * strSrc++) != ‘\0’ );
    }

      10分

    //為了實現鏈式操作,將目的地址返回,加3分!

    char * strcpy( char *strDest, const char *strSrc )
    {
     assert( (strDest != NULL) && (strSrc != NULL) );
     char *address = strDest;
     while( (*strDest++ = * strSrc++) != ‘\0’ );
      return address;
    }

      從2分到10分的幾個答案我們可以清楚的看到,小小的strcpy竟然暗藏著這么多玄機,真不是蓋的!需要多么扎實的基本功才能寫一個完美的strcpy?。?br />
      (4)對strlen的掌握,它沒有包括字符串末尾的'\0'。

      讀者看了不同分值的strcpy版本,應該也可以寫出一個10分的strlen函數了,完美的版本為: int strlen( const char *str ) //輸入參數const

    {
     assert( strt != NULL ); //斷言字符串地址非0
     int len;
     while( (*str++) != '\0' )
     {
      len++;
     }
     return len;
    }

      試題4:

    void GetMemory( char *p )
    {
     p = (char *) malloc( 100 );
    }

    void Test( void )
    {
     char *str = NULL;
     GetMemory( str );
     strcpy( str, "hello world" );
     printf( str );
    }

      試題5:

    char *GetMemory( void )
    {
     char p[] = "hello world";
     return p;
    }

    void Test( void )
    {
     char *str = NULL;
     str = GetMemory();
     printf( str );
    }

      試題6:

    void GetMemory( char **p, int num )
    {
     *p = (char *) malloc( num );
    }

    void Test( void )
    {
     char *str = NULL;
     GetMemory( &str, 100 );
     strcpy( str, "hello" );
     printf( str );
    }

      試題7:

    void Test( void )
    {
     char *str = (char *) malloc( 100 );
     strcpy( str, "hello" );
     free( str );
     ... //省略的其它語句
    }

      解答:

      試題4傳入中GetMemory( char *p )函數的形參為字符串指針,在函數內部修改形參并不能真正的改變傳入形參的值,執行完

    char *str = NULL;
    GetMemory( str );

      后的str仍然為NULL;

      試題5中

    char p[] = "hello world";
    return p;

      的p[]數組為函數內的局部自動變量,在函數返回后,內存已經被釋放。這是許多程序員常犯的錯誤,其根源在于不理解變量的生存期。

      試題6的GetMemory避免了試題4的問題,傳入GetMemory的參數為字符串指針的指針,但是在GetMemory中執行申請內存及賦值語句

    *p = (char *) malloc( num );

      后未判斷內存是否申請成功,應加上:

    if ( *p == NULL )
    {
     ...//進行申請內存失敗處理
    }

      試題7存在與試題6同樣的問題,在執行

    char *str = (char *) malloc(100);

      后未進行內存是否申請成功的判斷;另外,在free(str)后未置str為空,導致可能變成一個“野”指針,應加上:

    str = NULL;

      試題6的Test函數中也未對malloc的內存進行釋放。

      剖析:

      試題4~7考查面試者對內存操作的理解程度,基本功扎實的面試者一般都能正確的回答其中50~60的錯誤。但是要完全解答正確,卻也絕非易事。

      對內存操作的考查主要集中在:

     ?。?)指針的理解;

     ?。?)變量的生存期及作用范圍;

     ?。?)良好的動態內存申請和釋放習慣。

      再看看下面的一段程序有什么錯誤:

    swap( int* p1,int* p2 )
    {
     int *p;
     *p = *p1;
     *p1 = *p2;
     *p2 = *p;
    }

      在swap函數中,p是一個“野”指針,有可能指向系統區,導致程序運行的崩潰。在VC++中DEBUG運行時提示錯誤“Access Violation”。該程序應該改為:

    swap( int* p1,int* p2 )
    {
     int p;
     p = *p1;
     *p1 = *p2;
     *p2 = p;
    }

     3.內功題

      試題1:分別給出BOOL,int,float,指針變量 與“零值”比較的 if 語句(假設變量名為var)

      解答:

       BOOL型變量:if(!var)

       int型變量: if(var==0)

       float型變量:

       const float EPSINON = 0.00001;

       if ((x >= - EPSINON) && (x <= EPSINON)

       指針變量:  if(var==NULL)

      剖析:

      考查對0值判斷的“內功”,BOOL型變量的0判斷完全可以寫成if(var==0),而int型變量也可以寫成if(!var),指針變量的判斷也可以寫成if(!var),上述寫法雖然程序都能正確運行,但是未能清晰地表達程序的意思。


      const關鍵字至少有下列n個作用:

      (1)欲阻止一個變量被改變,可以使用const關鍵字。在定義該const變量時,通常需要對它進行初始化,因為以后就沒有機會再去改變它了;

     ?。?)對指針來說,可以指定指針本身為const,也可以指定指針所指的數據為const,或二者同時指定為const;

     ?。?)在一個函數聲明中,const可以修飾形參,表明它是一個輸入參數,在函數內部不能改變其值;

     ?。?)對于類的成員函數,若指定其為const類型,則表明其是一個常函數,不能修改類的成員變量;

     ?。?)對于類的成員函數,有時候必須指定其返回值為const類型,以使得其返回值不為“左值”。例如:

    const classA operator*(const classA& a1,const classA& a2);

      operator*的返回結果必須是一個const對象。如果不是,這樣的變態代碼也不會編譯出錯:

    classA a, b, c;
    (a * b) = c; // 對a*b的結果賦值

      操作(a * b) = c顯然不符合編程者的初衷,也沒有任何意義。

      剖析:

      驚訝嗎?小小的static和const居然有這么多功能,我們能回答幾個?如果只能回答1~2個,那還真得閉關再好好修煉修煉。

      這個題可以考查面試者對程序設計知識的掌握程度是初級、中級還是比較深入,沒有一定的知識廣度和深度,不可能對這個問題給出全面的解答。大多數人只能回答出static和const關鍵字的部分功能。

      4.技巧題

      試題1:請寫一個C函數,若處理器是Big_endian的,則返回0;若是Little_endian的,則返回1

      解答:

    int checkCPU()
    {
     {
      union w
      {
       int a;
       char b;
      } c;
      c.a = 1;
      return (c.b == 1);
     }
    }

      剖析:

      嵌入式系統開發者應該對Little-endian和Big-endian模式非常了解。采用Little-endian模式的CPU對操作數的存放方式是從低字節到高字節,而Big-endian模式對操作數的存放方式是從高字節到低字節。例如,16bit寬的數0x1234在Little- endian模式CPU內存中的存放方式(假設從地址0x4000開始存放)為:

    內存地址存放內容
    0x40000x34
    0x40010x12

      而在Big-endian模式CPU內存中的存放方式則為:

    內存地址存放內容
    0x40000x12
    0x40010x34

      32bit寬的數0x12345678在Little-endian模式CPU內存中的存放方式(假設從地址0x4000開始存放)為:

    內存地址存放內容
    0x40000x78
    0x40010x56
    0x40020x34
    0x40030x12

      而在Big-endian模式CPU內存中的存放方式則為:

    內存地址存放內容
    0x40000x12
    0x40010x34
    0x40020x56
    0x40030x78

      聯合體union的存放順序是所有成員都從低地址開始存放,面試者的解答利用該特性,輕松地獲得了CPU對內存采用Little-endian還是Big-endian模式讀寫。如果誰能當場給出這個解答,那簡直就是一個天才的程序員。

      試題2:寫一個函數返回1+2+3+…+n的值(假定結果不會超過長整型變量的范圍)

      解答:

    int Sum( int n )
    {
     return ( (long)1 + n) * n / 2;  //或return (1l + n) * n / 2;
    }

      剖析:
     
      對于這個題,只能說,也許最簡單的答案就是最好的答案。下面的解答,或者基于下面的解答思路去優化,不管怎么“折騰”,其效率也不可能與直接return ( 1 l + n ) * n / 2相比!

    int Sum( int n )
    {
     long sum = 0;
     for( int i=1; i<=n; i++ )
     {
      sum += i;
     }
     return sum;
    }

      所以程序員們需要敏感地將數學等知識用在程序設計中。
    posted on 2006-07-27 14:08 小力力力 閱讀(3543) 評論(2)  編輯  收藏 所屬分類: C/C++

    評論:
    # re: C/C++ 程序設計員應聘常見面試試題深入剖析 2006-10-22 11:32 | wj
    very good
    learn much from you  回復  更多評論
      
    # re: C/C++ 程序設計員應聘常見面試試題深入剖析 2007-06-18 16:11 | 果果
    謝謝  回復  更多評論
      
    主站蜘蛛池模板: 亚洲色偷偷综合亚洲av78 | 午夜爱爱免费视频| 亚洲精品线在线观看| 黄色网页在线免费观看| 国产免费无码AV片在线观看不卡 | 成人免费无遮挡无码黄漫视频| 亚洲精品视频免费观看| 亚洲免费在线视频观看| 88av免费观看| 亚洲色WWW成人永久网址| 精品成人免费自拍视频| 亚洲性日韩精品一区二区三区| 精品久久久久久久久亚洲偷窥女厕| 毛片免费在线观看网址| 亚洲国产精品成人精品小说| 7x7x7x免费在线观看| 亚洲精品在线观看视频| 精品一区二区三区免费毛片爱 | 午夜国产羞羞视频免费网站| 亚洲高清有码中文字| 夜夜爽免费888视频| 亚洲av无码国产综合专区| 又粗又大又黑又长的免费视频| 亚洲国产精品日韩在线观看| 欧洲一级毛片免费| 91嫩草亚洲精品| 97在线免费观看视频| 亚洲狠狠爱综合影院婷婷| 色一情一乱一伦一视频免费看| 91精品成人免费国产片| 亚洲精品无码久久毛片波多野吉衣| h视频在线观看免费完整版| 亚洲人成网站在线观看播放青青| 亚洲精品动漫免费二区| 亚洲av无码兔费综合| 亚洲福利精品电影在线观看| 两个人看的www免费视频中文| 亚洲国产精品VA在线观看麻豆 | 美女视频黄a视频全免费网站色| 亚洲国产成人精品女人久久久 | 日本一区午夜艳熟免费|