C語言指針和數組詳解

      常常在BBS上看到有人問指針和數組的問題。我曾經也很迷惑,現在,我談談我對指針和數組的理解。歡迎批評指正討論。

      1:定義數組

            int a[5];

            上一句定義了一個數組,名字叫a,它有5個元素,每個元素是int類型。換句話說,a是一個int [5]型的數組。int [5]表示的是類型,只不過是個複合類型,本質上,和int, float,double沒有區別,都是類型。

      2:數組的操作。

            2.1:sizeof操作。

                        像1中的數組a,sizeof(a)的值也就是sizeof(int [5])的值,也就是5*sizeof(int)的值。

            2.2:加、減、賦值。

                        當一個數組參與加、減和賦值運算的時候,它首先被轉換(converted to)成指向首元素的指針。

                        a+0是什麼?這裏數組a要做加法,所以,它首先被轉換成指向首元素的指針。然後再加0。
                        同理,a-0的操作過程是:a首先轉換成指向首元素的指針,再減0。

                        int *p = a;合法嗎?合法。數組a在賦值運算的時候,首先a轉換成指向首元素的指針,然後再賦值給p。

                        a+0,a-0和a,這三者有什麼區別?a+0的類型是int *,a-0的類型是int *,a的類型是int [5],也就是說類型有同。但它們的值是相同的,都是數組a首元素的地址。

            2.3 下標運算符[]

                        大家都知道,要訪問數組a的首元素,用a[0]就可以了。訪問第二個元素,用a[1]就可以了。

                        
那麼,[]究竟是什麼?表達式 E1[E2] 等同於表達式 *((E1)+(E2)),等同於*((E2)+(E1)),等同於E2[E1].

                        所以a[0]等同於*((a)+(0))即*(a+0)。a+0是指向首元素的指針,那麼*(a+0)就是首元素了。同理 a+1是指向第二個元素的指針,*(a+1)也就是第二個元素了。

            2.4 取地址運算符&。

                        &a是什麼?很明顯,&a是指向a的指針,a的類型是int [5],&a的類型就是int (*)[5]。&a的數值是數組a的首地址。

      3:所謂的多維數組。

            3.1 二維數組。

                  首先要明確,C語言中沒有真正的多維數組。C語言中的多維數組本質上是一維數組。

                  

3.1.1 定義

                        int b[3][5];

                        看上面的數組b的定義,b是一個一維數組,有3個元素,每個元素都像數組a一樣,也就是說,b的每個元素是int [5]。
                        既然所謂的二維數組還是一維數組,那麼我們所講述的一組數組的東西都可以用到所謂的二維數組上。

b是什麼?b是int [3][5]類型的變量。只不過這個變量不可被改變。

                  3.1.2 加、減、賦值。

                        b+0是什麼?b要做加法了,所以它首先被轉換爲指向首元素的指針,然後再加0。b的元素的類型是int [5],所以b+0的類型就是int (*)[5]。

                        b-0呢?同上。

                        int (*p1)[5] = b;是什麼意思?p1是一個指針,指向int [5]。把b賦值給它時候,b首先轉換成指向b的首元素的指針,再賦值。

                        *(b+0)的類型是什麼?b+0的類型是int (*)[5],那麼*(b+0)的類型就是int [5]。*(b+0)也就是數組b的第一個元素。*(b+1) 也就是數組b的第二個元素。

                        *(b+0)+0的類型是什麼?*(b+0)的類型就是int [5],那麼*(b+0)+0也就是指向這個整形數組的首元素的指針。也就是說*(b+0)+0的類型是int *型。

                        *(*(b+0)+0)的類型是什麼?*(b+0)+0是int *, *(*(b+0)+0)就是int。

                  3.1.3 下標運算符[]

                        E1[E2]不是和*((E1)+(E2))完全等同嗎,那麼*(*(b+0)+0)也就是*(b[0]+0)也就是b[0][0]。

                  3.1.4取地址運算符&

                        &b是什麼?很明顯,&b是指向b的指針,b的類型是int [3][5] ,&b的類型就是int (*)[3][5]。&b的數值是數組b的首地址。

            3.2 三維數組

                  int c[2][3][5]。c是個一維數組,有2個元素,每個元素都像b那樣,也就是說,每個元素都是個int [3][5]。

                  c+0是指針,類型是int (*)[3][5],指向c的第一個元素。

                  *(c+0)是第一個元素,也就是第一個int [3][5]。

                  *(c+0)+0是什麼?*(c+0)是int [3][5],*(c+0)+0就是指向*(c+0)中第一個int[5]的指針。

                  *(*(c+0)+0)是什麼?是個int [5]。

                  *(*(c+0)+0)+0是什麼?是指向上面的int [5]的第一個元素的指針。它的類型是int *。

                  *(*(*(c+0)+0)+0)是什麼?是第一個int。

      4:把數組傳給一個函數。

            把數組賦值給一個函數的參數,我們已經知道,賦值的時候數組首先轉換成指向首元素的指針。

            數組a可以傳給 void f1(int *arr)

            數組b可以傳給 void f2(int (*arr)[5])

            數組c可以傳給 void f3(int (*arr)[3][5])

            在上面三個函數裏,參數arr都是指針了,不再是數組了。所以,數組傳給函數的時候,會丟失維度的信息,所以,很多時候,把一個數組傳給函數時,還要用另一個參數指明數組是幾維的

      PS:

            數組名是指針?錯。

            數組名在+,-,賦值運算時被轉換爲指向數組首元素的指針?對。

            二維數組是二級指針?大錯特錯。數組就是數組。所謂的二維數組就是一維數組的數組。

            *(a+0)與a[0]完全一樣?對。不信就去查C99標準中的[]運算符。

            *(0+a)與0[a]完全一樣?對。不信去查標準。但寫成這樣蛋疼。

            a+0和a有什麼區別?區別大了。a是數組,a+0運算時,首先a被轉化成指向首元素的指針,然後再做指針加法。也就是說,a+0和a的數值一樣,類型不一樣。

            int *p=a;賦值運算時,a也被轉化爲指向首元素的指針?對。

            當數組a做爲參數傳給函數void foo(int a[])也被轉化爲指向首元素的指針?對。

            把b傳給函數,參數怎麼寫?void foo(int (*b)[5]),一個指向一組數組的指針。

            &a的類型是什麼?是int (*)[5]也就是指向一維數組的指針。但它的值還是a的首地址。

            如果你不太清楚int (*)[3][5]和int *[3][5]的區別,請google “右左原則”或訪問此網頁,然後在下載下來的東西里找“右左原則”四個字,讀過之後,對於聲明定義,都看得懂了。

本文來源:http://wildpointer.net/2010/06/10/c_pointer_array/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章