1. 程式人生 > >C高階篇(非BUG的語言特性)

C高階篇(非BUG的語言特性)

    許多新手程式設計師經常會犯的一種錯誤,就是將 i = 3; 與 i == 3 相互混淆,前者表示一個賦值語句,而後者常常作為判斷的條件。還有的程式設計師想將指標指向NULL時,寫成了p == NULL; 這樣的話變成了什麼?不過不用擔心,這種錯誤編譯器能夠辨別。
    NUL與NULL:在C語言中,NUL表示一個字串的結束,用字元表示為'\0',我們通常用'\0'這種字元常量作為判斷條件而不是NUL。NULL表示為空,用NULL表示什麼也不指向(即空指標)。
    switch、case、default:在用switch的時候,每個case後要加上一個break語句,除非你想讓後面的case一一執行,那樣看起來比沒使用switch還要麻煩。break語句總是靠近最近的迴圈語句或者switch語句,請注意你的程式碼風格,不要低估它的影響,它曾經導致AT&T歷史上第一次重大的網路癱瘓。程式碼如下:

    
    能看出只進行了case THING1: 然後直接跳出了整個switch嗎?

    在ANSI C下引入了一種新風格,如下:
    
    
    但是如果我們將s中的第四個字串後面的逗號去掉,那麼這個char指標就只有三個元素了,而後面的迴圈輸出的是四個元素。這樣會發生什麼錯誤?越界了,因為我們之前定義的字串常量只有三個,這裡卻引用了四個,第四個哪來的?問記憶體管理器去。

    C語言運算子優先順序存在的問題也有許多,例如說.運算子高於*,然而*p.f表示什麼?有人可能會誤解為(*p).f,但實際上是*(p.f)。
    []高於*,例如int *ap[],有人可能誤解為ap是個指向int陣列的指標,但實際上ap是個元素為int指標的陣列,也就是指標陣列。

    函式()高於*,例如int *fp(),有人可能誤解fp是個函式指標,函式返回int,但是實際上卻是返回int *的fp。
    總之,最好在我們辦公的位置上貼上一張優先順序表,方便檢視,在寫程式的時候也要時常注意。若我們對優先順序判斷失誤,整個程式碼的意思就有可能收到影響,我想象你不希望這樣。除了優先順序外,還要考慮語句的結合性,有些是左結合有些是右結合,當幾個操作符具有相同的優先順序時決定先執行哪一個。例如:
    int a,b = 2,c = 3;
    a = b = c;
    第二個語句賦值符優先順序都一樣,所以考慮其結合性,賦值符具有右結合性,就是說表示式中最右邊的操作最先執行,然後從右向做執行。最終a的值為3。


    早期gets()中的Bug導致了Internet蠕蟲,就在1988年11月,蠕蟲程式入侵了數千臺接入Internet的計算機,而最終原因卻是因為gets()函式沒有對讀入的字元數設定一個限制。我們知道字元陣列的空間是堆疊自動分配的,當用戶輸入超過了這個陣列的規定字元,gets()函式將會繼續把多出來的字元壓到堆疊中。如果黑闊想通過這些多餘的字元來改邪堆疊中某個專案的內容,那···不解釋,這個在高階技術貌似叫緩衝區溢位攻擊。可以用fgets來代替gets,例如:
    *c = fgets(s,sizeof(s),stdin);    //fgets(源,n-1字元數,欲讀取的流)
    這樣函式就不會超出緩衝區的範圍,也不會由於其他人執行程式而覆蓋堆疊中的重要區域。

    空格:許多人會告訴你空格在C語言中並沒有什麼意義,你喜歡的話可以隨便輸入幾個或者少輸入幾個,但事實並非如此!空格可以幫我們構造良好的程式碼風格,提高程式的通讀性。例如:z = y+++++x;
    這樣的話會出現編譯錯誤,但是我們加上必要的空格:z = y++ + ++x;
    還有另一種關於空格的錯誤,就是z = *x/*y; 表面上我們看到的是將兩個指標變數的值相除,但在仔細思考,我們發現/*是註釋符呀,這樣就出錯了。但是多加個空格z = *x / *y;

    是的,我們在用C進行開發的時候,可能會遇到由於C的語言特性產生的錯誤,這方面的案例太多太多了,有的因為將“,”寫成“.”而損失了上千萬。我想你一定不希望自己有這樣的遭遇,那麼就需要你留個心眼,考慮程式是否存在邏輯錯誤或者實體(語句)錯誤。