• <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>

            清風(fēng)竹林

            ぷ雪飄絳梅映殘紅
               ぷ花舞霜飛映蒼松
                 ----- Do more,suffer less

            Solmyr 的小品文系列之一:字符串放在哪里?

            畫外音:今天是個大晴天,溫暖的陽光透過窗子照進(jìn)了這間寬敞的辦公室,辦公室里三三兩兩的人們正在各自的計算機(jī)前努力工作,一切都顯得那么的安靜、祥和、有條不紊 ……

            啊~!救命啊!Solmyr 你又用文件夾砸我!”

            愚蠢者是應(yīng)該受到懲罰的。”

            畫外音: …… 呃,好吧,我得承認(rèn)有點小小的例外。這里是一家軟件公司,發(fā)出慘叫的這位是 zero ,新進(jìn)的大學(xué)生;這邊一臉優(yōu)雅,看上去很有修養(yǎng)一點也不象剛剛砸過人的這位,是 Solmyr ,資深程序員,負(fù)責(zé) zero 這一批新人的培訓(xùn)。啊,故事開始了 ……

            我干了什么啦?”zero 揉著鼻子問道,“這次你拿來砸我的文件夾又大了一號!”

            你過來自己看看你犯下的錯誤。”Solmyr 翻出了 zero 剛剛交上來的一段代碼:

            ……
            char* msg = “Connectting ... Please wait“
            ……
            if( Status == S_CONNECTED )
            strcpy(msg, “Connectted“);
            ……

            我犯了什么錯誤啦?這是一個很平凡的字符串聲明而已”,zero 不滿的說到。

            你看不出來嗎?connect 這個單詞的進(jìn)行時和過去時你都拼錯了,多打了一個 t”,Solmyr 不緊不慢地回答。

            就為了這個你又用文件夾砸我 …… ?。∵@次又是光盤盒!”

            這是商用軟件,你以為是在 QQ 上和 PPMM 聊天,有錯別字不要緊啊?更糟糕的是,我故意留了這么長的時間給你,到現(xiàn)在你還沒發(fā)現(xiàn)你真正的錯誤在什么地方。你可真不是一般的菜啊~”,Solmyr 故意拖了個長音,滿意的看到 zero 處于爆發(fā)的邊緣,“好吧,讓我們從基礎(chǔ)開始,C 語言中是怎樣處理字符串的?”

            這個我知道”,zero 顯得很有自信,“C/C++ 語言中,字符串是一段連續(xù)的字符型內(nèi)存單元,每個單元存放一個字符,并用\0 作為結(jié)尾的標(biāo)記。”

            那么使用指針之前,我們應(yīng)當(dāng) ……”

            我們應(yīng)當(dāng)保證這個指針指向合法的內(nèi)存,要么指向一塊已經(jīng)存在的內(nèi)存,要么為它動態(tài)分配一塊。”,zero 開始露出得意的笑容 —— 這種程度的問題,哈!

            好!那么你的代碼中 msg 這個指針指向哪里?”

            笑容凝固了。

            這個 …… 呃 …… 我想 …… 它應(yīng)該指向一塊合法內(nèi)存,因為以前我這么做的時候,它能工作 ……”,zero 期期艾艾的說。

            合法內(nèi)存?這塊內(nèi)存是誰分配的?它有多大?生存周期多長?有哪些特殊的性質(zhì)?”

            “……”

            唉!”,Solmyr 重重的嘆了口氣,“我就知道會這樣。好吧,讓我們先從簡單的開始。”。Solmyr 飛快的鍵入了如下代碼:

            char msg[] = “Hello“;

            char* pmsg = (char*)malloc( sizeof(“Hello“) );
            strcpy(pmsg, “Hello“);

            上面這些代碼你應(yīng)該都很清楚了:msg 是一個字符數(shù)組,C 語言保證會為它分配一段連續(xù)的內(nèi)存,并將其初始化為 “Hello“ pmsg 是一個字符指針,我們調(diào)用了 malloc 函數(shù)為它動態(tài)分配了一塊內(nèi)存,并用 strcpy 函數(shù)填充其值為 “Hello“ 。這兩種做法的共通點是:首先用正常手段獲得一段內(nèi)存,然后填充值。接著再來看這個:”

            char* msg = “Hello“;

            這一句代表什么意思?首先 msg 是個指針,C/C++ 語言不負(fù)責(zé)為它分配一塊內(nèi)存;其次我們也沒有顯式的為它分配一塊內(nèi)存。它指向哪里?指向 “Hello“ ,就是你直接寫在代碼里的那一個。”

            什么叫做‘直接寫在代碼里的那一個’?”,zero 露出了困惑的表情

            舉個例子你就明白了:”,Solmyr 再鍵入:

            double db = 1.5;

            這 一行里面,1.5 是個什么東西?它是一個 double 類型常量,C/C++ 語言要處理它們,也要分配內(nèi)存來存放這些東西。同理,當(dāng)你在代碼里寫了 “Hello“ ,實際上 C/C++ 語言就分配了一塊內(nèi)存存放這個字符串,當(dāng)你寫 char* msg = “Hello“ 的時候,你就是把這樣一塊內(nèi)存的地址賦給了指針 msg 。所以 msg 確實指向一塊合法內(nèi)存,這是有時候這段代碼能夠工作的原因。但是這樣做,其中蘊涵了許多問題,我來問你,指向這塊內(nèi)存的指針應(yīng)該是什么類型?”

            當(dāng)然是 char*”,zero 不加思索的回答。

            錯!應(yīng)該是 const char* 。想當(dāng)然耳,寫在程序中的字符串你不希望它發(fā)生變化,所以很明顯的,這塊內(nèi)存應(yīng)該被解釋為常量。但是你在聲明 msg 的時候做了什么?”

            呃 …… 我用了一個非常量的指針去指向了一個常量字符串。”,這一次,zero 明顯的審慎多了。

            正確??茨阍瓉淼拇a,你不僅用一個非常量指針指向它,而且還對這個指針執(zhí)行了 strcpy ,往里寫了內(nèi)容。在我們的編譯器上,這么做會引發(fā)什么后果?”

            呃 …… 引發(fā)一個運行時錯誤?”

            部分正確。準(zhǔn)確的講,只有在工程編譯選項為調(diào)試版本的時候,如果工程編譯選項為發(fā)布版本,一切都很正常 —— 奇怪嗎?并不,記住這一點:C/C++ 允許你打破任何保護(hù)。所以如果這兩行代碼在調(diào)試的時候沒有被發(fā)現(xiàn)而溜進(jìn)了發(fā)布版本里”,說到這,Solmyr 狠狠的瞪了 zero 一眼,“將會是很難發(fā)現(xiàn)的。”

            可是說來說去這么做還是沒有什么危害不是嗎?msg 指向一塊合法內(nèi)存,內(nèi)容正確,而且也并不是真的不能寫入,有什么好擔(dān)心的呢?”,zero 抱怨道。

            Solmyr
            順手抓起杯子,zero 反射性的立刻縮頭護(hù)臉。“別擔(dān)心,我只是喝水而已。”,Solmyr 面無表情 —— 如果忽略他嘴角那一絲壞笑的話 —— 的說到,“沒有危害是嗎?看看下面的代碼:”

            char* str1 = “Hello“;
            char* str2 = “Hello“;
            *str1 = ‘P‘;
            cout << str2 << endl;

            猜猜運行結(jié)果是什么?”,Solmyr 一邊調(diào)整工程設(shè)置,一邊問道。

            這還用問嗎?當(dāng)然是輸出 Hello 了。”

            回答錯誤,正確答案是 ……”,Solmyr 按下了運行按鈕,屏幕顯示的居然是 Pello !。

            zero
            大為詫異,撓著頭試圖找出其中的邏輯,突然間靈光一閃:“我明白了!str1 str2 實際指向同一段內(nèi)存!因為 C/C++ 語言在處理 Hello 字符串的時候把它當(dāng)作常量,所以就做了優(yōu)化,只保存了一份 Hello !是不是這樣!”zero 興奮的轉(zhuǎn)向 Solmyr。

            嗯, 看起來有時候你也不是那么菜么”,Solmyr 贊許的點頭,“不過你還是說錯了一點:這個不是 C/C++ 語言的做法,是這個編譯器的做法。簡單的說,你如果要對這種字符串寫的話,其結(jié)果如何,是沒有定義的。所謂沒有定義,就是 C/C++ 語言不保證會得到怎樣的結(jié)果,可能這樣也可能樣,完全決定于你的編譯器作者怎么想。想想看吧,哪天你的程序出現(xiàn)了古怪的問題 —— 比如顯示信息出現(xiàn)了混亂 —— 起因卻是你在無關(guān)的地方寫了一個字符串,會怎樣?這是維護(hù)時最大的惡夢之一?,F(xiàn)在你明白危害在哪里了?”

            zero
            有如大夢初醒一般忙不迭地點頭:“我知道了,我知道了。”

            知道了還不快去改!”

            ……

            zero
            跑回坐位修改他的程序去了,辦公室里再度恢復(fù)了寧靜,所有的人都埋頭于他們的工作之中。只有 Solmyr 一邊喝著咖啡一邊揉著太陽穴,喃喃地吐出不祥的詞句:“這樣的日子才剛剛開始啊 ……”

            posted on 2009-08-19 10:24 李現(xiàn)民 閱讀(548) 評論(0)  編輯 收藏 引用 所屬分類: 絕對盜版

            国产美女亚洲精品久久久综合| 色综合久久88色综合天天 | 无码任你躁久久久久久老妇App| 亚洲国产成人精品91久久久| 99久久国产亚洲综合精品| 久久精品亚洲精品国产色婷| 一级做a爱片久久毛片| 亚洲精品tv久久久久| 午夜精品久久久久久久| 国产精品成人无码久久久久久| 18禁黄久久久AAA片| 国产成人久久精品二区三区| 亚洲中文字幕无码久久精品1| 国产成人综合久久久久久| 亚洲av成人无码久久精品| 日韩十八禁一区二区久久| 久久美女网站免费| 精品久久久久久中文字幕大豆网| 精品久久久久久无码人妻热| 国内精品久久久久影院一蜜桃 | 精品久久人人爽天天玩人人妻| 99久久国产热无码精品免费久久久久 | 久久天天躁狠狠躁夜夜av浪潮| 久久精品国产亚洲AV高清热 | 久久成人国产精品二三区| 久久精品久久久久观看99水蜜桃| 久久乐国产精品亚洲综合| 丁香五月综合久久激情| 婷婷久久综合九色综合98| 97精品久久天干天天天按摩| 色综合久久久久无码专区| 久久影院综合精品| 久久99精品久久久久久动态图| 亚洲国产精品18久久久久久| 成人久久免费网站| 77777亚洲午夜久久多喷| 亚洲中文字幕无码久久精品1| 久久精品国产亚洲AV久| 欧美黑人又粗又大久久久| 老色鬼久久亚洲AV综合| 国内精品久久久久影院日本|