閱讀《C陷阱與缺陷》的知識增量

來源:互聯網
上載者:User

標籤:c語言   陷阱與缺陷   效率   效能   

看完《C陷阱與缺陷》,忍不住要重新翻一下,記錄一下與自己的慣性思維不符合的地方。記錄的是知識的增量,是這幾天的流量,而不是存量。
這本書是在ASCI C/C89訂製之前寫的,有些地方有疏漏。

第一章 詞法陷阱
  • 1.3 C語言中解析符號時使用貪心策略,如x+++++y將被解析為x++ ++ +y,並編譯出錯。
  • 1.5 單引號引起的一個字元代表一個對應的整數,對於採用ASCII字元集的編譯器而言,‘a‘與0141、97含義一致。
  • 練習1.1 嵌套注釋(如/*/**/*/)只在某些C編譯器中允許,如gcc4.8.2編譯時間是不支援的。
第二章 文法陷阱
  • 2.6 else始終與同一個括弧內最近的未匹配的if結合
第三章 語義陷阱
  • 3.1 int a[12][31]表示的是一個長度12的數組,每個元素是一個長度31的數組。
  • 3.1 在需要指標的地方如果使用數組名來替換,那麼數組名就被視為其下標為0的元素的指標,p = &a的寫法是非法的(gcc4.8.2隻是警告)。
  • 3.2 如何串連兩個給出的字串s、t?細節很重要,書中給出的答案如下:
char *r,*malloc()//原文稱不能直接聲明一個s、t長度之和的數組,但c99可以聲明變長數組,已經可以了//記得要把長度加1r = malloc(strlen(s) + strlen(t) +1);//必須判斷記憶體是否分配成功if(!r){    complain();    exit(1);}strcpy(r,s);strcat(r,t);......//完成之後一定要釋放rfree(r);
  • 3.6 如何正確計算數組的邊界?原則一,考慮最簡單情況下的特例;原則二,仔細計算邊界。
  • 3.6 以下一段代碼為何引起死迴圈?這是因為在記憶體位址遞減時,a[10]就是i。
    int i,a[10];for(i = 1; i<=10; i++)a[i] = 0;
  • 3.6 邊界的編程技巧:用第一個入界點和第一個出界點表示數值範圍,即[low,high)。這樣的效果是
    • 取值範圍的大小為兩者之差。
    • 若取值範圍為空白,則上界等於下界。
  • 3.6 --n一般比n--執行速度更快。
  • 3.7 運算子&&和||保證兩個運算元從左至右求值,其他運算子的運算元求值順序未定義。比如y[i] = x[i++]結果是未定義的。
  • 3.9 如何檢測a+b是否溢出?
    • if(a+b < 0)是不正確的,因為溢出時的行為是未定義的。正確的方法是將兩者轉換為unsigned型與INT_MAX比較
    • 更巧妙的方法:if(a > INT_MAX - b)
第四章 串連
  • 4.2 int a若出現在所有函數體之外,則完成了聲明與定義(分配儲存空間)。而extern int a;只是聲明,說明a的儲存空間是在其他地方分配的,不是定義;因此必須在別的某個地方定義,同一個或不同的源檔案均可。
  • 4.3 static修飾符可以將一個函數或變數的範圍限制在一個源檔案之內,不會與其他檔案中的同名量發生衝突
  • 4.5 聲明與定義必須嚴格相同,而數組和指標是不同的。
  • 4.6 如何避免聲明與定義不符?遵守“每個外部對象只在一個地方聲明”的規則即可。一般放在標頭檔中,所有用到此外部對象的源檔案都要包括此標頭檔,定義此對象的檔案也應該包括此標頭檔。
第五章 庫函數
  • 5.1 getchar()返回整數,不能把返回值賦值給char型變數再與EOF比較,因為EOF定義為-1,應該賦值給int型變數。
  • 5.2 如果要對檔案進行連續的read和write操作,則中間必須插入fseek函數調用。
  • 5.3 setbuf(stdout, buf);可以強制將buf指向的char數組設為緩衝區,改變輸出緩衝大小。
  • 5.3 書中使用緩衝區把stdin的內容複寫到stdout的程式是錯誤的,因為緩衝區內容的寫出直到緩衝區滿或調用fflush才開始完成。可以把buf聲明為靜態或者malloc在堆中,防止main函數結束後buf清空。
  • 5..1 一個程式異常終止時,程式輸出的最後一部分常常丟失,可以使用setbuf指向一個null 指標作為緩衝區
  • 5..2 putchar/getchar在stdio.h中使用宏實現,如果沒有包括stdio.h,很大可能仍能運行,但是使用相應的函數代替,速度降低。
第六章 前置處理器
  • 6 宏只是對文本處理,是一個運算式,不是函數或語句
  • 6.1 宏定義最好把每個參數和整個運算式使用括弧括起來防止出錯。
  • 6.2 如果一個運算元在兩個地方用到,將被求值兩次。解決方案:運算元應該沒有副作用;將宏實現為函數。
  • 6.2 宏可能產生非常龐大的運算式。
  • 6.3 宏的分號的使用很麻煩,assert的一種正確實現:#define assert(e) ((void)((e)||_assert_error(__FILE__,__LINE__)))
  • 6.4 typedef struct foo FOOTYPE是類型定義語句,定義了一個新的類型。
第七章 可移植性缺陷
  • 7.4 編譯器實現可能將字元當作有符號或無符號的。char轉換為int時結果未定義,可以使用unsigned char避免。
  • 7.4 將字元變數轉換為不帶正負號的整數時應該使用(unsigned char)c而不是(unsigned)c,後者將c轉換為int再轉換為unsigned int。
  • 7.5 除法運算速度大大慢於移位。
  • 7.7 整數除法運算時,僅規定商 x 除數 + 餘數 == 被除數,大多數實現在負數的除法時,只保證餘數與被除數加號或減號相同,商與被除數的符號無關。應盡量使n為無符號數。
  • 7.9 toupper/tolower函數均採用int型參數,實現時要檢查輸入是否符合要求,採用置位實現非常快速。
  • 7.11 要求一個按位輸出long型數字。需要考慮:不能對-n求值,可能溢出(邊界條件),應該把n轉換為負的再處理;餘數的符號未知,應做歸一化處理。
  • 7..2 atoi函數把字串轉換為long型整數,應該按照負數來處理以避免溢出。

  

轉載請註明Focustc,部落格地址為http://blog.csdn.net/caozhk,原文連結為點擊開啟
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.