c語言知識點補遺

2022-04-03 06:47:16 字數 2837 閱讀 4401

使用c很長時間,但是很難說對c的各個點都十分的透徹。雖然c不像c++那樣複雜,但是還有很多嘰裡旮旯兒:並不是他們有多難,而是在於他們平時用的不多,或者和人的第一直覺相悖,再或者初學時經驗有限理解不深根本沒有記住。

下面的這些東西可能來自《c專家程式設計》或者網路。最近發現基礎的經典的書籍常讀常新,原因可能有兩個:

1、隨著自己經驗的增長,你的認識可能會不一樣,思維的方式也會有所變化,而得到的東西自然會是新的東西。

2、早些時候經驗有限,有些點可能根本就沒有完全理解。現在你可以理解的更深刻。

這方面的書籍再比如《**大全》,前幾天翻了一下,又有不同的認識。

進入正題:

1、有符號和無符號的比較:

printf("%d\n", sizeof('a')):列印的值是4(或者是int的長度)而不是1。因為c有型別提公升,它會首先把'a'提公升為int型別,然後在傳給sizeof。表示式中的引數會提公升為int或者double,然後在進行運算,之後再進行裁剪,獲得指定型別的值

。if (-1 <= sizeof(int)):sizeof的返回值是unsigned int,-1會被型別轉換為unsignedint,然後在進行比較。。

這裡涉及到的是型別提公升,隱式型別轉換。它會在表示式中發生,也會在函式入參中發生。

2、列舉在記憶體中的大小:佔四個位元組。

3、區域性變數也是位元組對齊的:

e_t g;

e_t f;

e_t e = false;

char c1;

char c2;

int i1;

char c3;

int i2;

printf("%p, %p, %p, %p, %p, %p, %p, %p\n", &g, &f, &e, &c1, &c2, &i1, &c3, &i2);

--表示是補齊的位。

4、巨集定義中的#和##:#的功能是將其後面的巨集引數進行字串化操作(stringfication),簡單說就是在對它所引用的巨集變數通過替換後在其左右各加上乙個雙引號。

而##被稱為連線符(concatenator),用來將兩個token連線為乙個token。

5、浮點數不可以用等於比較。

6、void foobar2() 表示函式入參個數有多個,不確定。如果表示沒有產生,應該是:void foobar2(void)

7、全域性變數會被初始化為0,但是,棧中的區域性變數不會被初始化。

8、inline函式和巨集:內聯函式是真正的函式,但是它是在編譯期的優化。

9、    int a[5];    printf("%x\n", a);    printf("%x\n", a+1);    printf("%x\n", &a);    printf("%x\n", &a+1);

最後乙個,&a+1,&a表示陣列,所以,應該是增加陣列大小:4*5個位元組。

10、10u表示乙個無符號型別的數字10.

11、移位運算的優先順序比較低,低於四則運算。

12、左移n位,相當於乘與2的n次方。右移相當於處於2的n次方。

13、指標和陣列:

1)、void fun(char buf[100])

列印的值是4,而不是100。

2)、在乙個檔案中char p[10] = "";

在另外乙個檔案中宣告:extern char *p;

然後,在宣告的檔案中sizeof(p),答案是4。也就是,sizeof計算的是宣告的型別。

3)對於編譯器而言,乙個陣列就是乙個位址,乙個指標就是乙個位址的位址。

4)所有作為函式引數的陣列名編譯器都會轉換為指標,在其他所有的情況下,陣列的宣告就是陣列,指標的什麼就是指標。

陣列和指標相同情況的規則:

1、表示式中的陣列名(與宣告不同)被編譯器當作乙個指向該陣列的第乙個元素的指標。

2、下標總是與指標的偏移量相同。

3、在函式的宣告中,陣列名被編譯器當作指向該陣列第乙個元素的指標。這個操作時編譯器完成的。原因是出於效率的考慮。因為這樣就是引用傳遞而非值傳遞。值 傳遞需要拷貝。這也可以看的出sizeof是在彙編中操作的。

arry[-1]的行為是未定義的。

總結:1)a[i]這樣的形式對a進行訪問,總是被編譯器改寫為像*(a+i)的形式。

2)指標始終是指標,你不可以把它改寫成陣列,但是可以通過陣列的形式訪問。

3)陣列作為函式的引數,會被編譯器改寫成指標。

4)指標和陣列的什麼必須配對。

14、宣告與定義:宣告可以由多個,定義只有乙個。定義是特殊的宣告,它為物件分配了記憶體。而宣告時普通的宣告,描述其他地方建立的物件。

宣告的優先順序規則:

a:從他的名字開始按照優先次序依次讀取:

b:優先順序的高低:

1、宣告中被括號括起來的那部分。

2、字尾操作符:

括號()表示是乙個函式;

方括號表示是乙個陣列;

3、字首操作符:*表示指向什麼的指標;

4、const緊跟變數則修飾變數不可修改,緊跟型別則指向的東西不可修改。

15、多維陣列:

a[2][3]:a是乙個陣列,有兩個元素。每個元素又是乙個陣列,有三個元素。

記憶體布局:a[0][0],a[0][1],a[0][2],a[1][0]...位址一直變大。

多維陣列,陣列的陣列作為函式的形參,會被轉化為陣列指標,陣列的指標,也是行指標。本質上也是指標。

16、結構體預設的位元組對齊一般滿足三個準則:

1) 結構體變數的首位址能夠被其最寬基本型別成員的大小所整除;

2) 結構體每個成員相對於結構體首位址的偏移量(offset)都是成員自身大小的整數倍,如有需要編譯器會在成員之間加上填充位元組(internal adding);

3) 結構體的總大小為結構體最寬基本型別成員大小的整數倍,如有需要編譯器會在最末乙個成員之後加上填充字

c語言 知識點

遞迴方法 遞迴相比迴圈時間上快些,但是 遞迴比較占用空間,如果遞迴的次數超過十萬次後會導致資源占用完畢 標準的 優化技巧 消除迴圈 函式迴圈 函式 就地擴充套件 公共子表示式消除 改進暫存器分配 省略執行時對陣列邊界的檢查 迴圈不變數 移動 操作符長度消減 把指數操作符轉變為乘法操作 把乘法操作變為...

c語言知識點

2019 3 4 typedef void voidp 等同於typedef void voidp voidp a a null 即定義了乙個可以指向任何型別的指標 typedef voidpf zallback open file func of voidpf opeaque,const char...

c語言知識點

關於 va args define debug level,format,if level g printlevel else 這裡的 va args 表示可變引數,即上面.傳遞進來的多個引數,是當傳入引數為0時,去掉前面,防止編譯出錯 的另乙個用法如 define xname n x n,那xna...