轉(zhuǎn)本貼請把 win_hate 的名字寫上。
略談 c 語言中指針與數(shù)組的區(qū)別
數(shù)組與指針是兩個不同的概念,即使是從編譯的層面上來看。不過,在很多時候,兩者的用法極為相似。本文將討論兩者的區(qū)別。
一、理論分析
編譯器在處理指針與數(shù)組的時候,是區(qū)別對待的。
對于指針
p 是一個變量,所以編譯器要為之分配一個空間。
對于數(shù)組:
a 是一個地址,編譯器會為數(shù)組 a 分配一個空間,但不會為 a 本身分配空間,在使用到a的地方,會被替換為一個地址+屬性,其結(jié)果為一個"常量指針"。
在對一個指針變量進行 dereferance 的時候,比如 (*p)。編譯器首先要得到 p 的地址,從中取值,然后把得到的值作為地址,再取值。類似如下匯編:
lea (p), %esi /* this is &p */
mov (%esi), %edi /* this is p */
mov (%edi), %eax /* this is p[0] */
或者,更簡單的
mov (p), %esi /* this is p */
mov (%esi), %eax /* and this is p[0] */
相比之下,數(shù)組的引用
則省去了取 a 地址的過程,符號 a 代表一個地址,這個地址不存放在任何變量中!
lea (a), %esi /* this is a */
mov (%esi), %eax /* this is a[0] */
或更簡單的:
mov (a), %esi /* this is a[0] */
熟悉匯編的人,容易從看出,區(qū)別是大的。
二、兩個例子
第一個例子,演示 "把數(shù)組聲明為指針" 是如何使程序崩潰的。
file: 1.c
int a[10]={0};
file: 2.c
int
main ()
{
extern int *a;
printf ("%d\n", a[0]);
return 0;
}
運行這個程序,Segmentation fault
在模塊1.c 中, a 被定義為一個數(shù)組,但在模塊 2.c中,a被聲明為指針。所以編譯器在處理 printf ("%d\n", a[0]) 時:
認為 a 是一個指針,所以先取其地址&a,然而,a 實際是個數(shù)組,&a 就是 a本身,所的 &a 是 a 的首地址。
然后編譯器取 指針a的值,這實際上是 得到的是數(shù)組的第一個元素 a[0] ,值為0!也就是,編譯器得到了一個 0 指針,最后,編譯器對其derefrence,崩潰!
第二個例子演示“把指針聲明為數(shù)組”如何的到錯誤的數(shù)據(jù):
file: 3.c
int *pa = (int *)0;
f ()
{
printf ("%x\n", &pa);
}
file: 4.c
int
main ()
{
extern int pa[];
printf ("%p\n", pa);
printf ("%d\n", pa[0]);
f ();
return 0;
}
在這個例子中, pa 被定義為一個指針,并初始化為0, 但在另一個模塊中,被聲明為一個數(shù)組.
編譯器在處理 printf ("%p\n", pa) 時,認為 pa 是數(shù)組,所以直接打印符號pa的值,此值為指針pa的地址!
編譯器在處理 printf ("%p\n", pa[0]) 時,認為 pa 是數(shù)組,以符號 pa 對應(yīng)的值加一個偏移0,并取其值,得到的實際上是 指針 pa 的值 即 0.
三、總結(jié)
我羅羅嗦嗦地講了半天,如果還不清楚,請研究一下我給出的代碼。
[參考文獻]
[1] Peter Van Der Linden, <<Expert C Programming --- Deep C Secrets>;>;