陣列與指標分析

2021-06-16 18:08:49 字數 3962 閱讀 5663

指標就是指標,指標變數在32 位系統下,永遠佔4 個byte ,其值為某乙個記憶體的位址。指標可以指向任何地方,但是不是任何地方你都能通過這個指標變數訪問到。 

陣列就是陣列,其大小與元素的型別和個數有關。定義陣列時必須指定其元素的型別和個數。陣列可以存任何型別的資料,但不能存函式。

陣列的本質:

陣列是一段連續的記憶體空間

陣列的空間大小為  sizeof(array_type) * array_size

陣列名可看做指向陣列第乙個元素的常量指標,其值不能改變

指標的運算:

指標本質是變數,儲存的值被看做記憶體中的位址

指標是一種特殊的變數,與整數的運算規則為

p + n; (unsigned int)p + n*sizeof(*p);

指標之間只支援減法運算,且必須參與運算的指標型別必須相同

p1 - p2; ( (unsigned int)p1 - (unsigned int)p2) / sizeof(type);

注意:只有當兩個指標指向同乙個陣列中的元素時,指標相減才有意義,其意義為指標所指元素的下標查

當兩個指標指向的元素不在同乙個陣列中時,結果未定義

此處未定義含義:

1、當兩個指標分別指向棧空間和對空間上的陣列,則這兩個指標相減無意義

2、如同下例1,雖然兩個指標指向的陣列都在棧上,但是p0 - p2的值是由於記憶體對齊後相減得到的,也無意義

例1:char s1 = ;

int i = 0;

char s2 = ;

char* p0 = s1;

char* p1 = &s1[3];

char* p2 = s2;

int* p = &i;

printf("%d\n", p0 - p1);   //輸出-3

printf("%d\n", ((unsigned int)p0 - (unsigned int)p1) / sizeof(char));   //輸出-3,等價於上一句

printf("%d\n", p0 + p2);   //編譯報錯

printf("%d\n", p0 - p2);    //輸出-12,無意義

printf("%d\n", p0 - p);      //編譯報錯

printf("%d\n", p0 * p2);   //編譯報錯

printf("%d\n", p0 / p2);    //編譯報錯

指標的比較:

指標也可以進行關係運算    <    <=    >   >=

指標關係運算的前提是同時指向同乙個陣列中的元素

任意兩個指標之間的比較運算(==,!=)無限制

例2:#define dim(a) (sizeof(a) / sizeof(*a))

——以下摘自 陳正衝《c語言深度剖析》

以指標的形式訪問 和 以下標的形式訪問指標

char* p = "abcdef";

定義了乙個指標變數p ,p本身在棧上佔4 個byte ,p裡儲存的是一塊記憶體的首位址。這塊內存在常量區,其空間大小為7 個byte ,這塊記憶體也沒有名字。對這塊記憶體的訪問完全是匿名的訪問。比如現在需要讀取字元『e 』,我們有兩種方式: 

1)以指標的形式:*(p+4)。先取出p 裡儲存的位址值,假設為0x0000ff00,然後加上4 個字元的偏移量,得到新的位址0x0000ff04 。然後取出0x0000ff04 位址上的值。 

2)以下標的形式:p[4] 。編譯器總是把以下標的形式的操作解析為以指標的形式的操作。p[4]這個操作會被解析成:先取出p 裡儲存的位址值,然後加上中括號中4 個元素的偏 移量,計算出新的位址,然後從新的位址中取出值。也就是說以下標的形式訪問在本質上 與以指標的形式訪問沒有區別,只是寫法上不同罷了

以指標的形式訪問 和 以下標的形式訪問陣列

char a = "123456";

定義了乙個陣列a,a擁有7 個char 型別的元素,其空間大小為7 。陣列a 本身在棧上面。對a 的元素的訪問必須先根據陣列的名字a 找到陣列首元素的首位址,然後根據偏移量找到相應的值。這是一種典型的「具名+匿名」訪問。比如現在需要讀取字元『5 』,我們有兩種方式: 

1)以指標的形式:*(a+4)。a 這時候代表的是陣列首元素的首位址,假設為0x0000ff00,然後加上4 個字元的偏移量,得到新的位址0x0000ff04 。然後取出0x0000ff04 位址上的值。 

2)以下標的形式:a[4] 。編譯器總是把以下標的形式的操作解析為以指標的形式的操作。a[4]這個操作會被解析成:a 作為陣列首元素的首位址,然後加上中括號中4 個元素的偏移量,計算出新的位址,然後從新的位址中取出值。 

由上面的分析,我們可以看到,指標和陣列根本就是兩個完全不一樣的東西。只是它們都可以「以指標形式」或「以下標形式」進行訪問。乙個是完全的匿名訪問,乙個是典型的具名+匿名訪問。一定要注意的是這個「以*** 的形式的訪問」這種表達方式。 

另外乙個需要強調的是:上面所說的偏移量4 代表的是4 個元素,而不是4 個byte 。只不過這裡剛好是char 型別資料 1 個字元的大小就為1 個byte 。記住這個偏移量的單位是元素的個數而不是byte 數,在計算新位址時千萬別弄錯了。

下標 vs 指標

從理論上而言,當指標以固定增量在陣列中移動時,其效率高於下標產生的**

當指標增量為1且硬體具有硬體增量模型(硬體加速)時,表現更佳

注意:現代編譯器的生成**優化率已大大提高,在固定增量時,下標形式的效率已經和指標形式相當;但從可讀性和**維護角度來看,下標形式更優。

int a[10000];

int b[10000];

int* pend = &a[10000];

int* pa = null;

int* pb = null;

for(k=0; k<10000; k++)

}for(k=0; k<10000; k++)

;int* p1 = (int*)(&a + 1);     //p1[-1]   <==>   a[4] = 5

int* p2 = (int*)((int)a + 1); //p2[0]    <==>   0x02000000 十進位制為33554432

編譯執行

陣列引數

c語言中,陣列作為函式引數時,編譯器將其編譯成為對應的指標

void  f(int a);    void f(int* a);

void  f(int a[5]);  void f(int* a);

但丟失了長度資訊,所以一般情況下,當定義的函式中有陣列引數時,需要定義另乙個引數來標示陣列的大小。

例4:void f(int a[1000])      //會退化為void  f(int* a)

printf("%d\n",  sizeof(a));

int main()

int  a[5]  = ;

f(a);

return 0;

編譯執行,沒報錯

所以在作為函式引數時,陣列引數和指標引數等價

指標陣列和陣列指標分析

int指的是陣列元素的型別,而不是陣列的型別 定義陣列型別 c語言中通過typedef為陣列型別重新命名 typedef type name size 陣列型別 typedef int aint5 5 typedef float afloat10 10 陣列定義 aint5 iarray aint5...

指標與陣列,指標陣列 陣列指標

int a 10 print n a p,a p a,a print n a 1 p,a 1 p a 1,a 1 a做乙個指標,步長為4,指向乙個元素,a做乙個指標,步長為40,指向乙個維陣列 int b 3 4 print n b p,b p,b p b,b,b print n b 1 p,b 1...

指標陣列與陣列指標

1.指標陣列 指標陣列中每乙個元素都是乙個指標,也既是存放字串的首位址。所以指標陣列適合處理若干個長度不等的字串。定義的一般形式為 型別說明符 指標陣列名 陣列長度 例如 int p 3 宣告乙個陣列,指標陣列p,由3個int型別指標變數元素組成 從運算子的優先順序分析,由於 的優先順序大於 所以p...