C語言中的陣列指標與指標陣列

2021-06-10 11:08:00 字數 3621 閱讀 5053

一、指標陣列和陣列指標的記憶體布局

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

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

下面到底哪個是陣列指標,哪個是指標陣列呢:

a)int *p1[10];

b)int (*p2)[10];

這裡需要明白乙個符號之間的

優先順序問題

「[ ]」的優先順序比「 * 」要高。p1 先與「」結合,構成乙個陣列的定義,陣列名為p1,int *修飾的是陣列的內容,即陣列的每個元素。這是乙個陣列,其包含10 個指向int 型別資料的指標,即指標陣列。至於p2 ,「()」的優先順序「[ ]」高,「 * 」號和p2 構成乙個指標的定義,指標變數名為p2,int 修飾的是陣列的內容,即陣列的每個元素。陣列在這裡並沒有名字,是個匿名陣列。那現在我們清楚p2 是乙個指標,它指向乙個包含10 個int 型別資料的陣列,即陣列指標。我們可以借助下面的圖加深理解:

二、int (*)[10] p3

這裡有個有意思的話題值得**一下:平時我們定義指標不都是在資料型別後面加上指標變數名麼?這個指標p3 的定義怎麼不是按照這個語法來定義的呢?也許我們應該這樣來定義p3:

int (*)[10] p3;

int (*)[10]是指標型別,p3 是指標變數。這樣看起來的確不錯,但是彆扭。其實陣列指標的原型確實就是這樣子的

三、論a 和&a 之間的區別

看看下面的**:

int main()

;char (*p3)[5] = &a;

char (*p4)[5] = a;

return 0;

}上面對p3 和p4 的使用,哪個正確呢?p3+1 的值會是什麼?p4+1 的值又會是什麼?毫無疑問,p3 和p4 都是陣列指標,指向的是整個陣列。&a 是整個陣列的首位址,a是陣列首元素的首位址,其值相同但意義不同賦值符號「=」號兩邊的資料型別必須是相同的,如果不同需要顯示或隱式的型別轉換。p3 這個定義的「=」號兩邊的資料型別完全一致,而p4 這個定義的「=」號兩邊的資料型別就不一致了。左邊的型別是指向整個陣列的指標,右邊的資料型別是指向單個字元的指標。在visual c++6.0 上給出如下警告:

warning c4047: 'initializing' : 'char (*)[5]' differs in levels of indirection from 'char *'。

這裡雖然給出了警告,但由於&a 和a 的值一樣,而變數作為右值時編譯器只是取變數的值,所以執行並沒有什麼問題。警告你別這麼用。既然現在清楚了p3 和p4 都是指向整個陣列的,那p3+1 和p4+1 的值就很好理解了。

但是如果修改一下**,會有什麼問題?p3+1 和p4+1 的值又是多少呢?

int main()

;char (*p3)[3] = &a;

char (*p4)[3] = a;

return 0;

}甚至還可以把**再修改:

int main()

;char (*p3)[10] = &a;

char (*p4)[10] = a;

return 0;

}這個時候又會有什麼樣的問題?無法把int (*)[5]轉化為int (*)[10];p3+1 和p4+1 的值又是多少?

四、位址的強制轉換

先看下面這個例子:

struct test

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

p + 0x1 = 0x___ ?

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

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

乙個指標變數與乙個整數相加減,到底該怎麼解析呢?

指標變數與乙個整數相加減並不是用指標變數裡的位址直接加減這個整數。這個整數的單位不是byte 而是元素的個數。所以: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;

}分析分析這個問題:

根據上面的講解,&a+1 與a+1 的區別已經清楚。【&a + 1: 取陣列a 的首位址,該位址的值加上sizeof(a) 的值,即&a + 4*sizeof(int),也就是下乙個陣列的首位址,顯然當前指標已經越過了陣列的界限。a+1則是取a的位址,在加上int型別的大小,對指標進行加1 操作,得到的是下乙個元素的位址,而不是原有位址值直接加1。所以,乙個型別為t 的指標的移動,以sizeof(t) 為移動單位

】;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 的內容。

其記憶體布局如下圖:

問題就來了,這連續4 個byte 裡到底存了什麼東西呢?也就是說元素a[0],a[1]裡面的值到底怎麼儲存的。這就涉及到系統的大小端模式了,如果懂彙編的話,這根本就不是問題。既然不知道當前系統是什麼模式,那就得想辦法測試。我們可以用下面這個函式來測試當前系統的模式。

int checksystem( )

c;c.i = 1;

return (c.ch ==1);

}如果當前系統為大端模式這個函式返回0;如果為小端模式,函式返回1。也就是說如果此函式的返回值為1 的話,*ptr2 的值為0x2000000。如果此函式的返回值為0 的話,*ptr2 的值為0x100。

C語言中指標陣列與陣列指標

1 指標陣列的實質是乙個陣列,這個陣列中儲存的內容全部是指標變數。2 陣列指標的實質是乙個指標,這個指標指向的是乙個陣列。1 int p 5 int p 5 int p 5 2 一般規律 int p p是乙個指標 int p 5 p是乙個陣列 3 如果核心和 結合,表示核心是指標 如果核心和 結合,...

C語言中的陣列 指標陣列 陣列指標

1 include 2 3 int main 4 執行結果 0xbfeefda9 0xbfeefdaa 0xbfeefdab12 70xbfeefda9 0xbfeefdaa 0xbfeefdab12 7以上執行結果可以得出如下結論 char str 3 1 str i strr i 2 str i...

詳解C語言中的陣列指標與指標陣列

詳解陣列指標與指標陣列 陣列指標 一 區分 首先我們需要了解什麼是陣列指標以及什麼是指標陣列,如下圖 int p 5 int p 5 陣列指標的意思即為通過指標引用陣列,p先和 結合,說明了p是乙個指標變數,指向乙個大小為5的陣列。所以,int p 5 即為乙個陣列指標。int p 5 則是乙個大小...