C C 學習筆記 基礎知識11

2021-06-24 11:09:30 字數 3926 閱讀 4703

1指標陣列和陣列指標

(1)   指標陣列:首先它是乙個陣列,陣列的元素都是指標,陣列佔多少個位元組由陣列本身決定。它是「儲存指標的陣列」的簡稱。

陣列指標:首先它是乙個指標,它指向乙個陣列。在32位系統下永遠是佔4個位元組,至於它指向的陣列佔多少位元組,不知道。它是「指向陣列的指標」的簡稱

int *p1[10];

//「」的優先順序比「*」要高。p1先與「」結合,構成乙個陣列的定義,陣列名為p1,int *修飾的是陣列的內容,即陣列的每個元素。

//那現在我們清楚,這是乙個陣列,其包含10個指向int型別資料的指標,即指標陣列。

int (*p2)[10];

//至於p2,在這裡「()」的優先順序比「」高,「*」號和p2構成乙個指標的定義,指標變數名為p2,int修飾的是陣列的內容,即陣列的每個元素。

//陣列在這裡並沒有名字,是個匿名陣列。

//那現在我們清楚p2是乙個指標,它指向乙個包含10個int型別資料的陣列,即陣列指標。

(2) 位址的強制轉換

struct test

*p;

//假設p的值為0x100000。 如下表表示式的值分別為多少?

p + 0x1 = 0x___ ?

(unsigned long)p + 0x1 = 0x___?

(unsigned int*)p + 0x1 = 0x___?

p+0x1的值為0x100000+sizof(test)*0x1。至於此結構體的大小為20byte。所以p+0x1的值為:0x100014。

(unsigned long)p + 0x1的值呢?這裡涉及到強制轉換,將指標變數p儲存的值強制轉換成無符號的長整型數。任何數值一旦被強制轉換,其型別就改變了。所以這個表示式其實就是乙個無符號的長整型數加上另乙個整數。所以其值為:0x100001。

(unsigned int*)p + 0x1的值呢?這裡的p被強制轉換成乙個指向無符號整型的指標。所以其值為:0x100000+sizof(unsigned int)*0x1,等於0x100004

//在x86系統下,其值為多少?

int main()

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

int *ptr2=(int *)((int)a+1);

printf("%x,%x",ptr1[-1],*ptr2);

return 0;

}

ptr1:將&a+1的值強制轉換成int*型別,賦值給int* 型別的變數ptr,ptr1肯定指到陣列a的下乙個int型別資料了。ptr1[-1]被解析成*(ptr1-1),即ptr1往後退4個byte。所以其值為0x4。

ptr2:按照上面的講解,(int)a+1的值是元素a[0]的第二個位元組的位址。然後把這個位址強制轉換成int*型別的值賦給ptr2,也就是說*ptr2的值應該為元素a[0]的第二個位元組開始的

連續4個byte的內容。

//這個函式來測試當前系統的模式

int checksystem( )

c; c.i = 1;

return (c.ch ==1);

}

如果當前系統為大端模式這個函式返回0;如果為小端模式,函式返回1。

也就是說如果此函式的返回值為1的話,*ptr2的值為0x2000000。如果此函式的返回值為0的話,*ptr2的值為0x100

2二維陣列

記憶體不是錶狀的,而是線性的。記憶體的最小單位為1個byte。平時我們說記憶體位址為0x0000ff00也是指從記憶體零位址開始偏移0x0000ff00個byte。既然記憶體是線性的,那二維陣列在記憶體裡面肯定也是線性儲存的。char a[3][4]; 實際上其記憶體布局如下圖:

以陣列下標的方式來訪問其中的某個元素:a[i][j]。編譯器總是將二維陣列看成是乙個一維陣列,而一維陣列的每乙個元素又都是乙個陣列。

a[3]這個一維陣列的三個元素分別為:a[0],a[1],a[2]。每個元素的大小為sizeof(a[0]),即sizof(char)*4。

由此可以計算出a[0],a[1],a[2]三個元素的首位址分別為&a[0],& a[0]+ 1*sizof(char)*4,& a[0]+ 2*sizof(char)*4。亦即a[i]的首位址為& a[0]+ i*sizof(char)*4。

這時候再考慮a[i]裡面的內容。就本例而言,a[i]內有4個char型別的元素,其每個元素的首位址分別為&a[i],&a[i]+1*sizof(char),&a[i]+2*sizof(char),&a[i]+3*sizof(char),即a[i][j]的首位址為&a[i]+j*sizof(char)。

#include int main(int argc,char * argv)

; int *p;

p=a [0];

printf("%d",p[0]); //輸出1

}//花括號裡面巢狀的是小括號,而不是花括號!這裡是花括號裡面巢狀了逗號表示式!

//其實這個賦值就相當於int a [3][2]=;

//在初始化二維陣列的時候一定要注意,別不小心把應該用的花括號寫成小括號了

3陣列引數與指標引數無法向函式傳遞乙個陣列。

c語言中,當一維陣列作為函式引數的時候,編譯器總是把它解析成乙個指向其首元素首位址的指標。在c語言中,所有非陣列形式的資料實參均以傳值形式(對實參做乙份拷貝並傳遞給被呼叫的函式,函式不能修改作為實參的實際變數的值,而只能修改傳遞給它的那份拷貝)呼叫。然而,如果要拷貝整個陣列,無論在空間上還是在時間上,其開銷都是非常大的。更重要的是,在絕大部分情況下,你其實並不需要整個陣列的拷貝,你只想告訴函式在那一刻對哪個特定的陣列感興趣。這樣的話,為了節省時間和空間,提高程式執行的效率,於是就有了上述的規則。同樣的,函式的返回值也不能是乙個陣列,而只能是指標。這裡要明確的乙個概念就是:函式本身是沒有型別的,只有函式的返回值才有型別。實際傳遞的陣列大小與函式形參指定的陣列大小沒有關係

main函式內的變數不是全域性變數,而是區域性變數,只不過它的生命週期和全域性變數一樣長而已。全域性變數一定是定義在函式外部的

無法把指標變數本身傳遞給乙個函式

void getmemory(char * p, int num)

int main()

在執行strcpy(str,」hello」)語句的時候發生錯誤。這時候觀察str的值,發現仍然為null。也就是說str本身並沒有改變,我們malloc的記憶體的位址並沒有賦給str,而是賦給了_str。而這個_str是編譯器自動分配和**的,我們根本就無法使用。所以想這樣獲取一塊記憶體是不行的。那怎麼辦? 兩個辦法:

//第一:用return。

char * getmemory(char * p, int num)

int main()

//第二:用二級指標。

void getmemory(char ** p, int num)

int main()

// 注意,這裡的引數是&str而非str。這樣的話傳遞過去的是str的位址,是乙個值。在函式內部,用鑰匙(「*」)來開鎖:*(&str),其值就是str。所以malloc分配的記憶體地// 址是真正賦值給了str本身。

C C 學習筆記 基礎知識3

1 和 和 有什麼區別 1 和 對運算元進行求值運算,和 只是判斷邏輯關係。2 和 在在判斷左側運算元就能確定結果的情況下就不再對右側運算元求值。注意 在程式設計的時候有些時候將 或 替換成 或 沒有出錯,但是其邏輯是錯誤的,可能會導致不可預想的後果 比如當兩個運算元乙個是 1 另乙個是 2 時 2...

C C 學習筆記 基礎知識6

1複雜表示式與序列點 序列點是乙個時間點 在整個表示式全部計算完畢之後或在 或逗號運算子處,或在函式呼叫之前 此刻塵埃落定,所有的 都已確保結束.ansi iso c 標準這樣描述 在上乙個和下乙個序列點之間,乙個物件所儲存的值至多只能被表示式的計算修改一次。而且前乙個值只能用於決定將要儲存的值。i...

C C 學習筆記 基礎知識7

1字元和字串 在 c 語言中字元用它們的字符集值對應的小整數表示。因此,你不需要任何轉換函式 如有你有字元,你就有它的值。數字字元和它們對應的 0 9 的數字之間相互轉換時,加上或減去常數 0 也就是說,0 的字元值。字串用字元陣列表示 通常你操作的是字元陣列的第乙個字元的指標,c語言從來不會把陣列...