• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            統(tǒng)計

            • 隨筆 - 50
            • 文章 - 42
            • 評論 - 147
            • 引用 - 0

            留言簿(6)

            隨筆分類

            文章分類

            Link

            搜索

            •  

            積分與排名

            • 積分 - 165513
            • 排名 - 159

            最新評論

            閱讀排行榜

            評論排行榜

            從小函數(shù)實(shí)現(xiàn)看應(yīng)聘者的編程素質(zhì)(atoi.strcmp...)

            在程序員面試的時候,面試官通常會讓你實(shí)現(xiàn)一個或幾個C語言里的庫函數(shù),以此來檢查你的編程功底。類似的函數(shù)實(shí)現(xiàn)有atoi.itoa.atof.strcmp.strcpy.memset.memcpy等等。

            在平時的編程中,我們可能極少有機(jī)會要自己實(shí)現(xiàn)這些函數(shù)。但是面試官卻很喜歡用這些東西考察你。實(shí)際上所謂的"考察",永遠(yuǎn)是個偽命題。面試者其實(shí)不是用這個小函數(shù)的實(shí)現(xiàn)來考察"你行",而大部分寄希望于用這個小函數(shù)來"你不行"。隨便在網(wǎng)上搜搜,就會發(fā)現(xiàn)很多討論這個的帖子,其中大部分都有一些解答(用來證明你不行的理由),仔細(xì)琢磨就會發(fā)現(xiàn)其中的有一些還蠻有道理,但有一些解釋實(shí)在是有點(diǎn)牽強(qiáng)。

            說實(shí)話,這些函數(shù)實(shí)現(xiàn)的考察,作用還是有的,但是就我自己感覺,作用還不在單純的編程能力上,在本文的最后,我會發(fā)表我自己的一點(diǎn)看法。還是先說說這些函數(shù)的一些實(shí)現(xiàn),都是我自己比較認(rèn)可的版本,肯定也不一定完全符合面試官的要求,但無論如何,如果我碰到面試官這樣考我,我肯定拿下面的答案應(yīng)付了:)。

            首先來看看xtox系列的函數(shù),這類函數(shù)涉及數(shù)類型和字符類型之間的轉(zhuǎn)換,考察的一個知識點(diǎn)是如何將一個數(shù)字轉(zhuǎn)化為對應(yīng)的字符或者如何將對應(yīng)的字符轉(zhuǎn)化為數(shù)字(以下的代碼演示了這些轉(zhuǎn)換方法),在我知道這個方法以前,我都是寫個函數(shù),建立字符和數(shù)字的對應(yīng)查詢關(guān)系(相當(dāng)于建立了一個數(shù)字和字符的查詢快表)來匹配兩者的對應(yīng)關(guān)系。代碼應(yīng)該來說比較簡單,就不加注釋了,后文會提到需要額外說明的幾點(diǎn)。(特別說明:為篇幅計,下面的代碼出現(xiàn)了兩行代碼出現(xiàn)在一行的情況,真實(shí)的代碼中可能不希望這樣)

            -------------------------------------------------------atoi----------------------------------------------------------

            int atoi(const char* str)
            {
                int sign = 0,num = 0;
                assert(NULL != str);
                while (*str == ' ')
                {
                    str++;
                }
                if ('-' == *str)
                {
                    sign = 1; str++;
                }
                while ((*str >= '0') && (*str <= '9'))
                {
                    num = num*10 + (*str - '0'); //就是這一行,將對應(yīng)字符轉(zhuǎn)化為數(shù)字

                    str++;
                }
                if(sign == 1)
                    return -num;
                else
                    return num;
            }

            -------------------------------------------------atof------------------------------------------------------------

            double atof(const char* str)
            {
                double val = 0.0,power = 0.0;
                int sign = 0;
                assert(NULL != str);
                while (*str == ' ')
                {
                    str++;
                }
                sign = (*str == '-')? -1 : 1;
                if ('-' == *str || '+' == *str)
                {
                    str++;
                }
                while ((*str >= '0')&&(*str <= '9'))
                {
                    val = val* 10.0 + (*str - '0'); str++;
                }
                if ('.' == *str)
                {
                    str++;
                }
                power = 1.0;
                while ((*str >= '0')&&(*str <= '9'))
                {
                    val = val* 10.0 + (*str - '0');
                    power *= 10; str++;
                }
                return sign*val/power;
            }

            ---------------------------------------------itoa------------------------------------------------------------------------

            char* itoa(int val,char* buf,unsigned int radix)
            {
                char *bufptr;
                char *firstdig;
                char temp;
                unsigned int digval;
                assert(buf != NULL);
                bufptr = buf;
                if (val < 0)
                {
                    *bufptr++ = '-'; val = (unsigned int)(-(int)val);
                }
                firstdig = bufptr;
                do
                {
                    digval =(unsigned int) val % radix;    val /= radix;
                    if (digval > 9)
                    {
                        *bufptr++ = (char)(digval - 10 + 'a');
                    }
                    else
                    {
                        *bufptr++ = (char)(digval + '0');
                    }
                } while(val > 0);
                *bufptr-- = '\0';//設(shè)置字符串末尾,并將指針指向最后一個字符
                do //反轉(zhuǎn)字符
                {
                    temp = *bufptr;     *bufptr = *firstdig;  *firstdig = temp;
                    --bufptr; ++firstdig;
                } while(firstdig < bufptr);
                return buf;
            }

            ----------------------------------------------itoa.end-------------------------------------------------------------------

            下面是strxxx和memxxx系列,下面的一些實(shí)現(xiàn),有些我到現(xiàn)在還抱有一些疑問,比如說strcmp函數(shù),為什么要強(qiáng)制轉(zhuǎn)換成unisigned以及為什么要用*dst來判斷循環(huán)終止而不用*src,還沒有找到更好的答案或者徹底弄清楚這些問題,以后弄清楚了再補(bǔ)上。

            -------------------------------------------------------strcmp------------------------------------------------------------

            int strcmp(const char* src,const char* dst)
            {
                int ret = 0;
                if (src == dst)
                {
                    return 0;
                }
                assert(NULL != src);//期待源字符串不為空
                if (dst == NULL)
                {
                    return -1;
                }
                while (!(ret = *(unsigned char*)src - *(unsigned char*)dst)&& *dst)
                {
                    ++src,++dst;
                }
                if (ret < 0)
                {
                    ret = -1;
                }
                else if (ret > 0)
                {
                    ret = 1;
                }
                return ret;
            }

            -------------------------------------------strcpy------------------------------------------------------------------------

            char* strcpy(char* dst,const char* src)
            {
                char* strDst = dst;
                assert(src != NULL && dst != NULL);//拷貝空串被認(rèn)為是沒有意義的,使用assert檢查
                while ((*dst++ = *src++) != '\0')
                {
                    NULL;
                }
                return strDst;
            }

            --------------------------------------memcpy-------------------------------------------------------------------------

            void* memcpy(void* dst,const void* src,size_t count)
            {
                char* pbTo = (char*)dst;
                char* pbFrom = (char*)src;
                assert(dst!= NULL && src != NULL);
                assert(pbTo >= pbFrom+count || pbFrom >= pbTo + count);//防止內(nèi)存重疊(overlap)
                while (count-- > 0)
                {
                    *pbTo++ = *pbFrom++;
                }
                return dst;
            }

            --------------------------------------memmove---------------------------------------------------------------------

            void* memmove(void* dst,const void* src,size_t count)
            {
                char* pbTo = (char*)dst;
                char* pbFrom = (char*)src;
                assert(dst != NULL && src != NULL);
                if (dst <= src || pbTo >= pbFrom + count)//沒有overlap的情況,直接拷貝
                {
                    while (count-- > 0)
                    {
                        *pbTo++ = *pbFrom++;
                    }
                }
                else
                {
                    pbTo = pbTo + count -1;//overlap的情況,從高位地址向低位拷貝
                    pbFrom = pbFrom + count -1;
                    while (count-- > 0)
                    {
                        *pbTo-- = *pbFrom--;
                    }
                }
                return dst;
            }

            --------------------------------------memset-------------------------------------------------------------------------

            void* memset(void* buf,int c,size_t count)
            {
                char* pvTo = (char*)buf;
                assert(buf != NULL);
                while (count-- >0)
                {
                    *pvTo++ = (char)c;
                }
                return buf;
            }

            --------------------------------------memset.end---------------------------------------------------------------------

            這些函數(shù)的代碼都很短小,但是面試官對你這幾行短小的代碼抱有很高的期望。

            首先,正確性!實(shí)現(xiàn)得都不正確,那還搞毛啊,其他的小問題肯定談都不用談了,直接out!正確性要注意的地方,每個函數(shù)的功能起碼要了解(memmove等),邊界的檢查不能出錯;返回值也是要注意的地方。

            其次,assert不能少!對指針有效性的檢查是非常必要的,特別是在memcpy中,存在兩個assert,分別檢查指針的有效性以及內(nèi)存是否交疊。針對第二個assert還要加上必要注釋(因?yàn)榇a的維護(hù)者并不是一眼就能看出這個assert的涵義,搞不好可能直接在維護(hù)代碼中刪掉這么重要的一個assert檢查)。

            然后要注意的有:指針的有效性檢驗(yàn),最好是與NULL進(jìn)行比較。最后,空語句(strcpy)、大括號一個都不能少。

            我自己的想法,其實(shí)這些函數(shù)(包含其他小的函數(shù)),難度不算太大,當(dāng)然要寫得完全正確也非常不易。但是,在正確性的基礎(chǔ)上,面試官期望從你的代碼中發(fā)現(xiàn)你身上作為程序員的素質(zhì)和態(tài)度!當(dāng)我們編程的時候,我們的腦海里真的想的是手里敲的代碼嗎?當(dāng)我們正在實(shí)現(xiàn)一個函數(shù)或者一個類的時候,我們真的認(rèn)真考慮了它應(yīng)該怎樣被實(shí)現(xiàn)嗎?針對這些小函數(shù)(當(dāng)然,大函數(shù)更一樣了),參數(shù)的有效性檢查是always必要的(不要相信任何輸入!),邊界的有效性檢查是很容易出錯的!每一行代碼都要想清楚為什么要這么實(shí)現(xiàn),我想,只要你腦子所想是你手上所要做的,我手"寫"我心,自然是不會出錯了,起碼也應(yīng)該知道自己錯在哪里,下次改正就好。《微軟C編程精粹》最后一句話話告訴我們:成功地書寫無錯代碼的關(guān)鍵可以總結(jié)為一個總的原則,即絕不允許同樣的錯誤出現(xiàn)兩次!

            最后,推薦一些參考書,就我自己的閱讀經(jīng)驗(yàn)來看,這些參考書對如何寫好這些小函數(shù)還是很有借鑒意義的,按重要性排序:

            1.《編程精粹—微軟編寫優(yōu)質(zhì)無錯C程序秘訣》,Writing Clean Code——Microsoft Techniques for Developing Bug-free C Programs;

            2.《高質(zhì)量C\C++編程指南》,一本書,也是林銳編的,網(wǎng)上廣為流傳的同名小冊子算是精簡版;

            3.《程序員面試寶典》;

             

            本文來自CSDN博客,轉(zhuǎn)載請標(biāo)明出處:http://blog.csdn.net/winglet/archive/2008/08/26/2831605.aspx

            posted on 2009-08-24 15:17 pear_li 閱讀(3162) 評論(0)  編輯 收藏 引用 所屬分類: C++

            99久久精品毛片免费播放| 无码任你躁久久久久久老妇| 亚洲午夜福利精品久久| 久久久久久久综合狠狠综合| 欧美精品一区二区精品久久| 色偷偷888欧美精品久久久| 久久av高潮av无码av喷吹| 亚洲国产天堂久久综合| 久久久无码精品亚洲日韩蜜臀浪潮| 久久久国产精品福利免费| 日韩久久久久中文字幕人妻 | 久久久久人妻一区精品性色av| 波多野结衣中文字幕久久| 国产精品久久久久久久久久免费| 久久人人爽人人爽人人片AV不 | 亚洲欧美成人久久综合中文网| 亚洲国产精品无码久久一区二区| 国产精品成人久久久久三级午夜电影| 人妻无码αv中文字幕久久琪琪布 人妻无码精品久久亚瑟影视 | 久久久久亚洲精品天堂| 久久久噜噜噜久久| 日本久久久久久中文字幕| 欧美久久久久久| 久久久久国产一区二区| 亚洲国产天堂久久综合网站| 久久久久亚洲AV无码永不| 亚洲中文字幕久久精品无码喷水| 内射无码专区久久亚洲| 国内精品久久久久久久涩爱| 国产精品视频久久久| 99国产欧美精品久久久蜜芽| 亚洲精品tv久久久久久久久| 中文成人久久久久影院免费观看| 久久成人国产精品一区二区| 久久99亚洲网美利坚合众国| 亚洲中文字幕无码久久综合网| 国产成人精品综合久久久| 一本色道久久HEZYO无码| 久久亚洲国产成人精品性色| 久久精品午夜一区二区福利 | 久久人妻少妇嫩草AV无码专区|