指針學習之直觀展示多級指針運算原理的題目

以下是題目代碼:

    char a[4][3][2] = {
            {
                    {'a', 'b'}, {'c', 'd'}, {'e', 'f'}
            },
            {
                    {'g', 'h'}, {'i', 'j'}, {'k', 'l'}
            },
            {
                    {'m', 'n'}, {'o', 'p'}, {'q', 'r'}
            },
            {
                    {'s', 't'}, {'u', 'v'}, {'w', 'x'}
            }
    };
    char (*pa)[2] = &a[1][0];
    char (*ppa)[3][2] = &a[1];

題目要求:想要通過指針 pa 和 ppa 訪問數組 a 中的 'x' 元素,請問表達式應該怎麼寫? 

先不看答案,思考一下。

乍一看暈頭轉向的,二維數組就算了,居然出現三維數組。。。

其實三維數組本質和一維數組一樣的。

在一維數組中,我們如果想要訪問數組中某一元素的數據,除了使用數組下標法(即數組自己的內嵌指針)進行訪問,我們還可以自己定義指針來指向一維數組第一個元素,通過對指針存儲的地址進行運算,得到對應元素的地址並對地址進行解引用得到元素的值存儲的數據。

那麼同理,這個題目也是要求你使用指針來訪問數據,不過這個指針你不可以自己創建並指向三位數組的頭部,你需要用已定義的指針pa和ppa訪問數組a中的  'x' 元素。

我們還知道,定義數組時都是在內存中呈線性排列的,即倘若定義了int型一維數組,每個單位佔用四字節,數組長度是由決定,你定義多長內存就被拓展多長,二維數組也如此,只不過,二維數組的行元素包含列元素,更像外層一維數組包含內存一維數組, 例如 int [2][3] 就是內存中拓展了單位爲int型,總共佔用2*3個單位的二維數組,三位數組同理。

對char [4][3][2] 這個數組,單位長度爲1字節,內存中就是拓展了2*3*4 = 24(字節)的長度。

已定義的指針爲 char (*pa)[2] = &a[1][0];  指針pa爲跨度爲2單位,它指向的是a[1][0]即{ 'g','h' }這個元素,因爲是線性排列,我們只需要讓它向後移動8個pa的跨度即pa + 8,來指向{ 'w','x' }這個元素,即得到{ 'w','x' }的地址,得到地址不等於數據,需要解引用*(p+8),但是數組是二維數組,解引用之後得到的還是一維數組指針的地址,不過這個一級指針的地址可以幫我們準確拿到'x'的地址,我們對地址運算:*(p+8)+1得到'x'的地址,進一步解引用*(*(p+8)+1)就可以得到數據x。

爲了方便敘述,我把最內層的一維數組叫一級數組,中間一層的一維數組叫二級數組,最外層的一維數組叫三級數組。

對於 char (*ppa)[3][2] = &a[1]; 指針ppa跨度爲3*2 = 6個單位,它指向的是a[1]即 { {'g', 'h'}, {'i', 'j'}, {'k', 'l'} }這一個等級的元素的,這一元素跨度就是6單位,我們對直接對ppa進行運算,跨度也是6,我們對ppa+2,得到三級數組第三個元素 { {'s', 't'}, {'u', 'v'}, {'w', 'x'} }的地址,解引用*(ppa+2)可以得到此元素包含的二級數組[ {'s', 't'}, {'u', 'v'}, {'w', 'x'} ]的指針存放的地址,對這個地址+2得到二級數組第三個元素的地址,即*(ppa+2)+2,解引用後*(*(ppa+2)+2)得到一級數組[ {'w', 'x'} ]的指針存放的地址,對這個地址加1得到x地址並再次解引用*(*(*(ppa+2)+2)+1)得到數據x。

綜上所述,*pa 被定義爲一個一維數組,其跨度爲 2 個字節,所以 *(pa + 8) 指向的是 {'w', 'x'} 這個數組,所以 *(*(pa + 8) + 1) 取出 'x' 元素;*ppa 被定義爲一個二維數組,其跨度爲 6 個字節,所以 *(ppa + 2) 指向的是 {{'s', 't'}, {'u', 'v'}, {'w', 'x'}} 這個二維數組,所以 *(*(*(ppa + 2) + 2) + 1) 取出 'x' 元素。

答案分別是:*(*(p+8)+1)  ,*(*(*(ppa + 2) + 2) + 1)

定義指針爲什麼要定義爲數組指針的意義也在這裏,目的就是不讓指針在進行運算過程中只是單純的+1。如果只是單純定義指針爲三級指針***p ,那麼對p運算時不論如何解引用後運算,不論對哪一級指針進行運算都是單純的+1。而且既然你既然能拿到具體數據的地址,還費那麼大力氣幹嘛,直接賦值給*p不就行了,所以我認爲***p沒有多大意義,當然對付指針數組存放字符串時,**p還是有用的,因爲只需要拿到數組內 存放的字符串的地址(這個地址就是字符串指針的地址)就可以用%s輸出每個字符了。

***p是賦值的時候將二級指針的地址賦值給三級指針的時候常用的,因爲編譯器對於指針的賦值左右是必須爲同等級的指針,你不能把一個二級指針的地址賦予給一個一級指針。所以當創建了三維數組就可以拿到數組內具體元素的地址,這個地址我們可以賦值給一級指針,因爲他是數據元素,但我們拿到一級數組整體的地址時,即拿到了指針的地址,這時我們就必須創建二維數組來存放這個地址了。同理***p僅僅是可以存放二維數組整體地址即二維數組指針的地址。

 

 

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