总结:数组名和指针完全是两码事
? 大家經常接觸到諸如:“數組名可以當作指向數組首元素的指針用”、“指針可以用數組下標方式進行訪問”這些事實,所以數組和指針的概念經常被混淆,其實數組和指針是完全不同的兩種類型,下面本文分析一些常常被人們忽略的事實。
1.數組和指針是兩種完全不同的類型
int arr[10] = {0,1,2,3,4,5,6,7,8,9}; int *p_arr = arr;? 數組名arr代表著內存中有一塊連續的區域,這個區域存儲了10個int變量,它的大小在編譯時已經確定(動態數組除外)。
? 指針名p_arr代表著內存中的可以一個塊,這個塊的大小為足夠表示地址的大小,這個塊的內容是一個int變量所在的地址。
在內存中是這個樣子:
Object Address 0x00 0x01 0x02 0x03 ------ ------- ----------------------arr 0x10008000 0x00 0x00 0x00 0x010x10008004 0x00 0x02 0x00 0x030x10008008 0x00 0x04 0x00 0x050x1000800c 0x00 0x06 0x00 0x070x10008010 0x00 0x08 0x00 0x09parr 0x10008014 0x10 0x00 0x80 0x00【應用】 ?
這就解釋了讓人困擾的sizeof問題:
? 為什么sizeof(arr)返回數組總大小,sizeof(p_arr)只返回指針大小?
? 答:arr代表數組這塊內存區域,編譯后其大小就是固定的已知的,所以sizeof可以讀出其大小。
2.數組和指針都可通過下標訪問,但訪問途徑有所不同。
? 上面的例子中,用arr[i]和p_arr[i]的效果完全一樣。但是內部實現有所差別!
| 數組下標訪問時arr[i]: |
| |
| arr對應編譯器符號表有個地址add0 運行時步驟一:取i的值與add0相加得add1=add0+i 運行時步驟二:取add1的內容 | p_arr對應編譯器符號表有個地址add0 運行時步驟一:取add0的內容add1=(add0) 運行時步驟一:取i的值與add1相加得add2=add1+i 運行時步驟二:取地址add2的內容 |
可見指針下標訪問方式比數組多一次取地址步驟,即指針是間接訪問、數組時直接訪問。
【應用】
解釋了:1).如果arr在一個文件中定義為數組,把它再另一個文件中聲明為指針后,進行訪問會錯誤。2).如果p在一個文件中定義為指針,把它在另一個文件中聲明為數組后,訪問仍會錯誤。
?
3.數組和指針下標符號的本質
?
定義:a[i]?is identical to?(*((a)+(i)))
?
當數組下標訪問時arr[i],其實是這樣:(*(arr+i))。arr+i運算時數組名arr就轉換為了指向首元素的指針,所以會和指針下標有同樣的效果。
?
這個定義也意味著:a[i]與i[a]其實是等價的,大家可以實驗。
?
另外,對起始地址執行加法之前,編譯器負責計算每次增加的步長。
如int *的指針p,p+1時會執行地址+4而不是+1。
所以,每種指針必須有一種類型的原因是:編譯器需要知道 1)對指針解引用操作時應該取幾個字節 2)下標的步長應該取幾個字節
?
?
4.數組名不能轉換為指針的情況
數組名在許多場合會自動轉換為指向數組首元素的指針(函數傳參、賦值給指針、表達式),但有些場合不會發生轉換。
我所知道的有兩種情況:sizeof操作符和&取地址操作符。
sizeof上面已經講過。
我們看看arr和&arr的差別:
1 int arr[10] = {0,1,2,3,4,5,6,7,8,9}; 2 int *p = arr; 3 int (*ap)[10] = &arr; 4 5 printf("before: arr = %p, p = %p, ap = %p\n", (void *) arr, (void *) p, (void *) ap); 6 p++; 7 ap++; 8 printf("after: arr = %p, p = %p, ap = %p\n", (void *) arr, (void *) p, (void *) ap);運行結果:
before: ?arr = 0xbfbb96a0, p = 0xbfbb96a0, ap = 0xbfbb96a0
after: ? ?arr = 0xbfbb96a0, p = 0xbfbb96a4, ap = 0xbfbb96c8
可以看出ap指向的是整個數組,當ap++后指針往后移動了40個字節。
?
?5.指針和數組在“定義時初始化”的不同
定義指針時,除了字符串常量的情況,編譯器不為指針所指向的對象分配空間,只分配指針本身的空間。
char *p = "abcde"; //正確,但這個字符串存是只讀的int *p = 5; //錯誤,不能給除了字符串以為的常量分配空間定義數組時不存在這個問題。
?
6.數組名是不可修改的左值,指針是可修改的左值
左值:代表地址,表示存儲結果的地方,在編譯時可知。
右值:代表地址的內容,直到運行時才知。
數組名用于確定對象在內存中的位置,是左值,可是不能被賦值。如:
?
int arr1[10], arr2[10]; main() {int *p;arr1 = arr2; //錯誤,數組名不能被賦值p = arr1; //正確,指針可以被賦值 }?
?
?
?
?
轉載于:https://www.cnblogs.com/renzhe688/p/3365894.html
總結
以上是生活随笔為你收集整理的总结:数组名和指针完全是两码事的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: bitmap 位图
- 下一篇: 学习笔记-记ActiveMQ学习摘录与心