C陷阱與缺陷(學習筆記)

2021-10-14 06:01:19 字數 2887 閱讀 7289

掌握細節並不難,難的是如何運用之妙!

詞:單詞

符號=作為賦值運算,是因為操作頻繁,書寫簡單

a—b與表示式a – - b的含義相同,而與a - – b的含義不同

y = x/*p與y = x / *p不同(第乙個/*被理解為注釋符)

理解:這也許就是編碼規範要求操作符兩側新增合理空格的原因之一吧

用雙引號引起的字串,代表的卻是乙個指向無名陣列起始字元的指標。

字元』\0』對應的十進位制是0

括號(),陣列下標,函式呼叫,結構成員選擇操作符->/. > 單目運算子 > 算數運算子 > 移位運算子 > 關係運算子 > 邏輯運算子 > 賦值運算子 > 條件運算子(三目運算子)

*p++,先計算p++

while (c=getc(in) != eof)和while ((c=getc(in)) != eof)

case語句結束時不加break的場景,最好加上注釋// fall-through

練習題:

為什麼c語言允許初始化列表**現多餘的逗號,如:

int a = ;

enum ;

據說是為了簡化**生成工具的邏輯處理。

c語言中的陣列值得注意的地方有以下兩點:

c語言中只有一維陣列,而且陣列的大小必須在編譯期就作為乙個常數確定下來。然而,c語言中陣列的元素可以是任何型別的物件,當然也可以是另外乙個陣列。這樣,要「**」出乙個多維陣列就不是一件難事。

(備註:c99標準允許變長陣列(vla))

對於乙個陣列,我們只能夠做兩件事:確定該陣列的大小,以及獲得指向該陣列下標為0的元素的指標。其他有關陣列的操作,哪怕它們乍看上去是以陣列下標進行運算的,實際上都是通過指標進行的。換句話說,任何乙個陣列下標運算都等同於乙個對應的指標運算,因此我們完全可以依據指標行為定義陣列下標的行為。

「欄杆錯誤」,也常被稱為」差一錯誤「(off-by-one error)

問題:100英呎長的圍欄每隔10英呎需要一根支撐用的欄杆,一共需要多少根欄杆?

解決方法:用第乙個入界點和第乙個出界點來表示乙個數值範圍,即[a, b)

如:x>=16且x<=37,表示成:x>=16且x<38

這個問題,還會出現在:佇列,棧等緩衝區操作中

#define n 1024

static char buffer[n];

static char *bufptr;

bufptr = buffer;

……if (bufptr == &buffer[n])

c語言中只有四個運算子(&&、||、?: 和,)存在規定的求值順序。

運算子&&和||首先對左側運算元求值,只在需要時才對右側運算元求值

運算子?:有三個運算元:在a?b:c中,運算元a首先被求值,根據a的值再求運算元b或c的值

逗號運算子,首先對左側運算元求值,然後該值被」丟棄「,再對右側運算元求值。

」溢位「,是指有符號整數算術運算中發生的現象

#define f (x)  ((x)-1)

#define f(x) ((x)-1)

#define max(a,b) ((a)>(b) ? (a) : (b)),每個引數用括號括起來,整個結果表示式也用括號括起來

max(a++, b),引數不能出現***,a會被計算兩次

避免巨集展開成龐大的表示式,如:max(a,max(b,max(c,d)))

assert巨集

#define assert(e) if (!e) assert_error(__file__, __line__)

例子:

if (x > 0 && y > 0)

assert(x > y);

else

assert(y > x);

展開後:

if (x > 0 && y > 0)

if (!(x > y)) assert_error("foo.c", 37);

else

if (!(y > x)) assert_error("foo.c", 39);

問題:出現了if和else重新組隊。

#define assert(e)

展開後:

if (x > 0 && y > 0)

;else

;

問題:else之前的分號是乙個語法錯誤

#define assert(e) ((void)((e) || assert_error(__file__, __line__)))

展開後:

if (x > 0 && y > 0)

((void)((x > y)) || assert_error("foo.c", 37)));

else

((void)((y > x)) || assert_error("foo.c", 39)));

理解

if, else**塊加{},所以**規範一般要求,即便只有一條語句的**塊也要加{}

根據巨集具體作用定義形式,有的需要定義成表示式,有的需要定義成語句塊(用do while(0)包裹巨集內容)

#define t1 struct foo *

typedef struct foo * t2;

t1 a, b; // 擴充套件為:struct foo * a, b; 乙個是指標變數,乙個是結構體變數

t2 a, b;

C陷阱與缺陷 筆記

這本書很薄,看目錄感覺講的也很基礎,估計能較快看完。算是開始閱讀前陣子買的那波書的熱身吧。學過編譯原理,我們應當了解,編譯器的工作基本過程。在詞法分析中,不同編譯器的不同設定,會帶來不同的問題。雖然很是細微,但是如果出錯,可能編譯器不提示,讓人抓狂.int a 0195 int b 0215 int...

C陷阱與缺陷 筆記

fortan formula translator 公式翻譯程式語言 fibonacci 斐波那契 為什麼n 的含義是n 0,而不是n 0?a b的含義是?賦值操作符為什麼是 而不是 ascii碼 貪心原則?10是否能表示成010?單引號括起來的乙個字元表示乙個整數,雙引號括起來的乙個字元代表乙個指...

C陷阱與缺陷筆記

第一章 詞法陷阱 1.1 不同於 1.2 與 不同於 與 1.3 詞法分析中的 貪心法 1.4 整型變數 1.5 字元與字串 第二章 語法陷阱 2.1 理解函式宣告 2.2 運算子的優先順序問題 2.3 注意作為語句結束標誌的分號 2.4 switch語句 2.5 函式呼叫 2.6 懸掛 else引...