C語言高階剖析 29 指標和陣列分析(下)

2021-10-01 03:53:40 字數 4114 閱讀 3951

2 a 和 &a 的區別

3 陣列引數

4 小結

在開始之前,先思考乙個問題:陣列名可以當作常量指標使用,那麼指標是否也可以當作陣列名來使用呢?

訪問陣列中的元素有兩種訪問方式,通過下標訪問和通過指標訪問陣列

下標形式和指標形式基本是等價的,但是效率略有區別

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

下標形式與指標形式之間可以相互轉換,轉換如下:

這裡 a[n] 可是可以轉換為 n[a] 的哦

下面通過乙個例子說明陣列的指標訪問和下標訪問

// 29-1.c

#include

intmain()

;int

* p = a;

int i =0;

for(i =

0; i <

5; i++

)for

(i =

0; i <

5; i++

)printf

("\n");

for(i =

0; i <

5; i++

)for

(i =

0; i <

5; i++

)return0;

}

編譯執行結果如下:

$ gcc 29-1.c -o 29-1

$ ./29-1

a[0] = 1

a[1] = 2

a[2] = 3

a[3] = 4

a[4] = 5

p[0] = 10

p[1] = 11

p[2] = 12

p[3] = 13

p[4] = 14

從結果我們可以看到,通過指標和陣列都可以實現訪問陣列中的元素,可以把陣列名當作常量指標使用,也可以把指標當作陣列名來使用,a[i] 和 i[a] 是等效的

指標和陣列的概念不是完全相等的,二著是有區別的,我們通過乙個例子來說明指標陣列和指標的不同

// 29-2.c

#include

intmain()

// ext.c

int a=

;

編譯執行結果如下:

$ gcc 29-2.c ext.c -o 29-2

$ ./29-2

&a = 0x560167697010

a = 0x560167697010

*a = 1

a 是陣列首元素的位址,&a 是整個陣列的位址,在數值上二者是相同的,*a 表示取元素第乙個元素。

如果把 29-2.c 的第 6 行 extern int a; 改為 extern int *a; **更改如下:

// 29-2.c

#include

intmain()

再次編譯執行,結果完全不一樣了

$ gcc 29-2.c ext.c -o 29-2

$ ./29-2

&a = 0x562f0c0ba010

a = 0x200000001

段錯誤 (核心已轉儲)

為什麼會出現這個執行結果呢?編譯器編譯 ext.c 後,陣列 a 的位址就是 0x562f0c0ba010,等價於 a 的位址就是 0x562f0c0ba010。編譯 29-2.c 時,碰見 extern int* a; 就尋找其他位置定義的 a 的值,a 的位址為 0x562f0c0ba010,所以 &a 就是取 a 的位址,就是 0x562f0c0ba010,a 的值是該位址下對應的資料,為 0x200000001。*a 表示取位址值為 0x200000001 的資料,不合法,是不允許訪問的,返回段錯誤。

下面來說明一下為什麼位址 0x562f0c0ba010 對應的資料為 0x200000001,我們列印的是 %p,%p 代表的是:按十六進製制輸出資料,長度為 8 個位元組,linux 是小端序系統,低位址存放低位,陣列儲存方式如下,取 8 位元組資料為 0x200000001

a + 1 表示指向下乙個元素,a + 1是越過乙個元素,&a + 1 表示指向這個陣列最後乙個元素後面的位置,&a + 1 是越過乙個陣列,可以從下圖清晰的看到二者的指向

下面看乙個例子,更好的區分 a 和 &a

結論:將陣列名作為引數傳遞給函式時,陣列名退化為指標,一般情況下,當定義的函式中有陣列引數時,需要定義另乙個引數來表示陣列的大小

下面通過例子來驗證我們的理論

// 29-4.c

#include

void

func1

(char a[5]

)void

func2

(char b)

intmain()

;func1

(array)

;printf

("array[0] = %c\n"

, array[0]

);func2

(array)

;printf

("array[0] = %c\n"

, array[0]

);return0;

}

在 func1() 函式中,,列印 sizeof(a),陣列退化成指標,所以不管陣列長度如何,列印的都是指標的長度,由於退化成指標,所以允許 修改指標 a = null; 我們是不能修改陣列名的指向的。func1() 函式是一樣的,只是沒有指定陣列長度。

編譯執行結果如下:

$ gcc 29-4.c -o 29-4

$ ./29-4

in func1: sizeof(a) = 8

array[0] = a

in func2: sizeof(b) = 8

array[0] = b

1、陣列名和指標僅使用方式相同,陣列名本質不是指標,指標也不是陣列名

2、陣列名並不是陣列的位址,而是陣列首元素的位址

3、函式的陣列引數退化為指標

29 指標和陣列分析(下)

注 部落格中內容主要來自 狄泰軟體學院 部落格僅當私人筆記使用。測試環境 ubuntu 10.10 gcc版本 4.4.5 一 問題 陣列名可以當做指標常量使用,那麼指標是否也可以當做陣列名來使用呢?二 陣列的訪問方式 1 以下標的形式訪問陣列中的元素 int main a 1 3 a 2 5 re...

複習c語言深度剖析 28 指標和陣列分析(上)

陣列的本質 陣列是一段連續的記憶體空間 陣列的空間大小為sizeof array type array size 陣列名可看做指向陣列第乙個元素的指標常量。問題 a 1的意義是什麼?結果是什麼?指標運算的意義是什麼?結果是什麼?include int main int p null printf a...

C 28 指標和陣列分析

問題 a 1的意義是什麼?結果是什麼?指標運算的意義是什麼?結果是什麼?程式設計分析 a 1 示例 include int main int p null printf a 0x x n unsigned int a printf a 1 0x x n unsigned int a 1 陣列名看著常...