C語言要點

2021-06-09 16:24:28 字數 3959 閱讀 4112

一關鍵字: 1.

static:

第乙個作用:修飾變數。變數又分為區域性和全域性變數,但它們都存在記憶體的靜態區。由於被static修飾的變數總是存在記憶體的靜態區,所以即使這個函式執行結束,這個靜態變數的值還是不會被銷毀,函式下次使用時仍然能用到這個值。

static int j;

void fun1(void)

void fun2(void)

int main()

return 0;

第二個作用:修飾函式。函式前加static使得函式成為靜態函式。但此處「static」的含義不是指儲存方式,而是指對函式的作用域僅侷限於本檔案(所以又稱內部函式)。使用內部函式的好處是:不同的人編寫不同的函式時,不用擔心自己定義的函式,是否會與其它檔案中的函式同名。

2 .sizeof

sizeof是關鍵字不是函式

3. signed、unsigned關鍵字

4. float變數與「零值」進行比較

5.if else語句

先處理正常情況,再處理異常情況。

6.迴圈語句風格

在多重迴圈中,如果有可能,應當將最長的迴圈放在最內層,最短的迴圈放

在最外層,以減少cpu 跨切迴圈層的次數。

7. void

void不能代表乙個真實的變數

void a; //錯誤

function(void a); //錯誤

8.const

const修飾的唯讀變數必須在定義的同時初始化,編譯器通常不為普通const唯讀變數分配儲存空間,而是將它們儲存在符號表中,這使得它成為乙個編譯期間的值,沒有了儲存與讀記憶體的操作,使得它的效率也很高。

a)修飾指標

const int *p; // p 可變,p指向的物件不可變

int const *p; // p可變,p指向的物件不可變

int*const p; //p不可變,p指向的物件可變

const int *const p; //指標p和p指向的物件都不可變

b)修飾函式引數

const修飾符也可以修飾函式的引數,當不希望這個引數值被函式體內意外改變時使

用。例如:

void fun(const int i);

9.extern

extern就相當於他們的這些區別於中國人的特性。extern可以置於變數或者函式前,以

標示變數或者函式的定義在別的檔案中。

10.struct

空結構體的大小就定位1個byte。struct的成員預設情況下屬性是public的,而class成員卻是private的。

11.union

union維護足夠的空間來置放多個資料成員中的「一種」,而不是為每乙個資料成員配置空間,在union中所有的資料成員共用乙個空間,同一時間只能儲存其中乙個資料成員,所有的資料成員具有相同的起始位址。例子如下:

union statemachine ;

乙個union只配置乙個足夠大的空間以來容納最大長度的資料成員.

12 typedef

二預處理

1.#if

#if 的一般含義是如果#if後面的常量表示式為true,則編譯它與#endif之間的**,否則跳過這些**。命令#endif 標識乙個#if塊的結束。#else命令的功能有點象c語言中的else ,#else建立另一選擇(在#if 失敗的情況下)。#elif命令意義與else if 相同,它形成乙個if else-if階梯狀語句,可進行多種編譯選擇。

2.#define

#define會原樣替換,要搞定它其實很簡單,別吝嗇括號就行了。

例子:

定義乙個巨集函式,求x 的平方:

#define sqr (x) x * x

試試:假設x 的值為10,sqr (x)被替換後變成10*10。沒有問題。

再試試:假設x 的值是個表示式10+1,sqr (x)被替換後變成10+1*10+1。問題

這並不是我想要得到的。怎麼辦?括號括起來不就完了?

#define sqr (x) ((x)*(x))

三指標和陣列

注意!!!:指標的偏移值是起始位址加上指標指向物件的size。

1.陣列名a作為左值和右值的區別

陣列名不能作為左值,對指標進行加1操作,得到的是下乙個元素的位址,而不是原有位址值直接加1。所以,乙個型別為t的指標的移動,以sizeof(t) 為移動單位。main() ;

int *ptr=(int *)(&a+1);

printf("%d,%d",*(a+1),*(ptr-1)); }

&a + 1: 取陣列a的首位址,該位址的值加上sizeof(a) 的值,即&a + 5*sizeof(int),也

就是下乙個陣列的首位址,顯然當前指標已經越過了陣列的界限。(int *)(&a+1):則是把上一步計算出來的位址,強制轉換為int * 型別,賦值給ptr。*(a+1): a,&a的值是一樣的,但意思不一樣,a是陣列首元素的首位址,也就是a[0]的首位址,&a是陣列的首位址,a+1是陣列下一元素的首位址,即a[1]的首位址,&a+1是下乙個陣列的首位址。所以輸出2*(ptr-1): 因為ptr 是指向a[5],並且ptr是int * 型別,所以*(ptr-1)是指向a[4] ,輸出5。

2.陣列和指標的關係

檔案1中定義如下:

char a[100];

檔案2 中宣告如下:

extern char *a;

這裡,檔案1 中定義了陣列a,檔案2中宣告它為指標。這有什麼問題嗎?平時不是總說陣列與指標相似,甚至可以通用嗎?但是,很不幸,這是錯誤的。通過上面的分析我們也能明白一些,陣列就是陣列,指標就是指標,它們是完全不同的兩碼事!他們之間沒有任何關係,只是經常穿著相似的衣服來迷惑你罷了。下面就來分析分析這個問題:

定義和宣告之間的區別,定義分配的記憶體,而宣告沒有。定義只能出現一次,而宣告可以出現多次。這裡extern告訴編譯器a這個名字已經在別的檔案中被定義了,下面的**使用的名字a是別的檔案定義的。再回顧到前面對於左值和右值的討論,我們知道如果編譯器需要某個位址(可能還需要加上偏移量)來執行某種操作的話,它就可以直接通過開鎖動作(使用「*」這把鑰匙)來讀或者寫這個位址上的記憶體,並不需要先去找到儲存這個位址的地方。相反,對於指標而言,必須先去找到儲存這個位址的地方,取出這個位址值然後對這個位址進行開鎖(使用「*」這把鑰匙)。如下圖:

這就是為什麼extern char a與extern char a[100]等價的原因。因為這只是宣告,不分配空間,所以編譯器無需知道這個陣列有多少個元素。這兩個宣告都告訴編譯器a是在別的檔案中被定義的乙個陣列,a 同時代表著陣列a的首元素的首位址,也就是這塊記憶體的起始位址。陣列內地任何元素的的位址都只需要知道這個位址就可以計算出來。

但是,當你宣告為extern char *a時,編譯器理所當然的認為a是乙個指標變數,在32位系統下,佔4個byte。這4個byte裡儲存了乙個位址,這個位址上存的是字元型別資料。雖然在檔案1中,編譯器知道a 是乙個陣列,但是在檔案2中,編譯器並不知道這點。大多數編譯器是按檔案分別編譯的,編譯器只按照本檔案中宣告的型別來處理。所以,雖然a實際大小為100個byte,但是在檔案2中,編譯器認為a 只佔4個byte。

我們說過,編譯器會把存在指標變數中的任何資料當作位址來處理。所以,如果需要

訪問這些字元型別資料,我們必須先從指標變數a中取出其儲存的位址。如下圖:

顯然,按照上面的分析,我們把檔案1中定義的陣列在檔案2 中宣告為指標會發生錯誤。同樣的,如果在檔案1中定義為指標,而在檔案中宣告為陣列也會發生錯誤:

檔案1char *p = 「abcdefg」;

檔案2extern char p;

在檔案1 中,編譯器分配4個byte空間,並命名為p。同時p裡儲存了字串常量「abcdefg」的首字元的首位址。這個字串常量本身儲存在記憶體的靜態區,其內容不可更改。在檔案2中,編譯器認為p是乙個陣列,其大小為4 個byte,陣列內儲存的是char型別的資料。在檔案2中使用p 的過程如下圖:

3. 陣列引數與指標引數

無法向函式傳遞乙個陣列,c語言中,當一維陣列作為函式引數的時候,編譯器總是把它解析成乙個指向其首元素首位址的指標。

C語言解惑要點

1 運算子的優先順序 2 型別轉換 2.1 有符號與無符號數 結果輸出為 2 2 1 2147483647 1 2147483647 2.2 浮點數與整數 3 控制流 這一部分主要需要注意if else之間的巢狀時的配對情況,及迴圈語句的終止條件與狀態。4 轉義字元 除了 n t這一類的轉義字元,還...

C語言指標要點

乙個有效的指標必然是以下三種狀態之一 儲存乙個特定物件的位址 指向某個物件後面的另乙個物件 或者是0值 注意只能是0常量的表示式,或者直接0。絕對不能來個變數0 int pi2 ival pi2 0 int pi3 dangerous,because pi3 is uninitialized一定要避...

c語言struct要點

struct struct name c 裡面struct和class是基本上一樣的 似乎預設的成員乙個是public乙個是private 並且c 在宣告乙個class struct後可以直接用classname structname來宣告例項 struct class tempname tempn...