我相信很多人都跟我一樣被某些書害的不淺,在C語言中一直還把指針跟數組名混為一談。其實它們跟本就是兩樣的東西,指針就是指針,數組就是數組,網上也有很多大牛作過很多非常深入的討論,但是個人感覺有時候把問題想得太復雜了反而不好,尤其是對於新手,因為我們新手很難搞懂編譯器背着我們到底都干了些什么。我們有時候應該透過現象看本質,但有時候也不要太鑽牛角尖,一口吃不出個胖子,必要時“難得糊塗”,站在抽象的角度去看事情,很多所謂的“本質”歸根到底就是“規則”,讓我們返朴歸真看看標准是怎么說的,對於新手關於數組和指針的區別和以及什么時候“相同”只要記住《c專家編程》中提到的三個標准和三個例外就可以了:
規則1."表達式中的數組名被編譯器當作一個指向該數組第一個元素的指針。"
規則2."下標總是與指針的偏移量相同。
規則3."在函數參數的聲明中,數組名被編譯器當作指向該數組的第一個元素的指針。"
在下列的情況下,對數組的引用不能用指向該數組第一個元素的指針來代替:
例外1.數組作為sizeof()的操作數,顯然此時需要的是整個數組的大小,而不是所指向第一個元素的大小
例外2.使用&操作符取數組的地址
例外3.數組是一個字符串常量初始化值
一個很簡單的例子:
#include <stdio.h> char ga[]="abcdrfghik"; void method(char ca[])//or char *ca { printf(" addr of arrary param = %#x \n",&ca); //規則3 printf(" (*ca) = %c \n",*ca); printf(" addr (ca[0]) = %#x \n",&(ca[0])); printf(" addr (ca[1]) = %#x \n",&(ca[1])); printf("++ca = %#x \n\n",++ca); } int main(void) { //例外2 這個只是數組和指針能夠互換的一個例外。這里ga代表數組,這個獲取的數組的地址 printf(" addr of arrary param = %#x \n",&ga); //規則1 printf(" (*ga) = %c \n",*ga); printf(" addr (ga[0]) = %#x \n",&(ga[0])); printf(" addr (ga[1]) = %#x \n",&(ga[1])); //例外1 printf(" sizeof ga = %d \n\n",sizeof(ga)); method(ga); return 0; }
另外,
“數組名被改寫成一個指針的參數”規則並不是遞歸定義的。數組的數組會被改寫成“數組的指針”而不是“指針的指針”
比如char c[8][10]所被改寫對應的形參為 char (*)[10],為“數組的指針”。
一個簡單的例子:
#include <stdio.h> #include <malloc.h> method(int a[3][2]) { int i=0; int j=0; for(i=0;i<=2;i++) { for(j=0;j<=1;j++) { printf("%d\n",a[i][j]); } } for(i=0;i<=2;i++) { for(j=0;j<=1;j++) { printf("%d\n",*(*(a+i)+j)); } } int k=0; for(k=0;k<=5;k++) { //a是指向 int (*)[2] 的行指針,*a即為二位數組的首行首元素的地址 printf("%d\n",*(*a+k)); } } int main(void) { int a[3][2]={{1,2},{3,4},{5,6}}; method(a); return 0; }
至於更深層的知識水到自然渠成。