指標破解 上)指標和陣列

2021-08-19 14:01:47 字數 4116 閱讀 6321

初期接觸指標時,我們大都是對指標進行簡單的解引用賦值等操作,指標的操作物件大都是int或者char等基本型別,所以簡單理解後便可以輕鬆應對。

但是,就如同剛學會騎自行車後就要飛向賽博坦星球(汽車人老家),基本的int *,char *還沒有掌握完全,取而代之的是各種形態各種變化的「機械」怪物

(指標等複雜的宣告),尚未反應過來就已經被繞的頭暈目眩。

對於複雜的宣告,萬變不離其宗。就如同交通工具一般,需要引擎,輪子,方向盤。無論二手奧拓還是布加迪威龍,都離不開這核心的部分。所以我們從c語言中的宣告入手,破解指標的複雜纏繞

int * arr[10]

void * test(char *dest,int sz)

以上分別是對指標、指標陣列、函式的宣告,通過簡單分析可得,乙個宣告中一般都需要 變數名、字尾操作符(來判斷是函式還是陣列)、字首操作符(判斷元素或者函式的返回值型別),將這三個要素拿捏在手,那麼其他問題都會迎刃而解

指向陣列的指標,稱之為陣列指標

c語言中每種型別都有對應的操作方法,比如將乙個整型賦值給乙個指向整型的指標就需要強制型別轉換,即在右值前鍵入(int *)來進行轉換。如果沒有進行強制型別轉換,將不同的型別強制賦值,編譯器就會發出警告,並且後續的操作有可能發生截斷,導致運算出現匪夷所思的差錯。

例如將char *型別的指標p賦值int型別運算元的位址,那麼p+1將僅僅跳過乙個位元組的記憶體來進行讀取,然而int型別的記憶體位元組數為4,那麼解引用就會發生截斷,導致結果出錯。

一般當我將陣列名當作引數傳遞給函式時,此時傳遞的僅僅時陣列首元素的首位址,對於整型陣列,那麼它傳遞的就是第乙個元素,也就是第乙個整型的位址來進行操作,它指向的是單個整型值。

對於二維陣列而言,int arr[2][3]它的陣列名是也是第首元素的首位址,但此時它的首元素是arr[0],它又包含了乙個含有三個整型的一維陣列,那麼此時,我們傳入的就是乙個指向一維陣列的指標,宣告如下

int(*p)[3]
同第一部分宣告一樣,對其進行分析

其實指標宣告的核心是沒有改變的,先看名字,再看型別,再看內容的相關資訊

對於宣告int *p而言,就好比這是自行車,p為騎車的人,*p結合後我們知道騎的是交通工具而不是騎在別人脖子上,哪種交通工具?28自行車(int *)。

對於一維陣列的指標,顯然要比int高階一點,他要指向一段連續的空間,自行車顯然是解決不了問題的,所以座駕公升級!電動自行車!

如何讓編譯器知道我們騎的是電動自行車呢?他的宣告顯然跟28自行車不同。(*p)後的[3]表示這個電動車的電池容量,int表示它還是兩個輪子的,這些資訊都很關鍵,所以編譯器知道了這些資訊,才能給我們把路鋪好然後盡情馳騁。

是的。十分明了,指標陣列,就是指標的陣列,point在陣列。

int

*(*p)[3]

同理,p先與*結合,表示它是指標,字尾表示它指向的是乙個有三個元素的陣列,字首一看,int *表示每個元素是指向整型的指標。

所以,p是乙個指向包含三個元素的每個元素為int *的陣列的指標

那麼如果表示儲存了三個上述指標的指標陣列?

int *(*arr

[3])[3]

同樣分析,arr先同[3]結合,表示它是乙個包含三個元素的陣列,然後同字首*結合,表示它的元素型別是指標,現跳出括號看字尾[3],表示每個元素指向乙個包三個元素的陣列,現在又跳向字首int *表示該陣列每個元素的型別是int *

所以,陣列arr是乙個有三個元素,每個元素是指標,指向有三個元素,元素型別為int*的指標陣列的指標陣列

是的,這太繞了,我們這麼做值是為了理解它。

第一部分的宣告已經對函式部分的宣告有了初步的介紹

void * test(char *dest,int sz)

其中test為函式名,表示該函式的位址

void *(*p)(char *,int);
函式指標依然遵循上述原則,首先p與*結合表示這是乙個交通工具(指標)。現在看字尾操作符,發現是()函式呼叫操作符,它的引數型別分別是char *和int,(它的引擎不同,是全新發動機),字首是void *,噢,原來他是電單車(函式的返回型別是void*)

所以,指標p是指向引數為char* ,int 的返回值型別為void*的函式

有了上述的經驗,那麼就會很容易寫出函式指標的陣列的宣告

void *(*arr[3])(char *,int );
首先,arr與字尾操作符[3]結合,表示它為乙個陣列,現與*結合,表示的元素型別為指標,現跳出括號,發現是函式呼叫操作符,引數的型別是char* ,int型別。再次跳轉到最前方,發現函式的返回值型別為void*。

所以,陣列arr是乙個有三個元素,每個元素是指向引數型別分別為char*,int的返回值型別為void *的函式指標的陣列

不成威脅,都是紙老虎。

void *(*(*p)[3])(char*,int)
首先,p與*集合,表示它是乙個指標,緊接著,與字尾操作符[3]集合,表示這個指標指向乙個包含三個元素的陣列,緊接著再同括號內最前面操作符*結合,表示每個元素的型別為指標。現在跳出括號後方同樣為函式呼叫操作符,引數的型別是char* ,int型別。再次跳轉到最前方,發現函式的返回值型別為void*。

所以,p是乙個指向有三個元素,每個元素又是指向引數型別為char ,int。返回值型別為void 的函式指標的陣列的陣列指標

void (*signal(int,void(*)(int)))(int)
請解釋上述宣告的意思

老規矩.先看變數名,發現字尾操作符是函式呼叫操作符,優先順序高於*,率先結合,表示signal是乙個引數型別為int,void(*)(int)(該為函式指標的型別符),的函式,然後字首操作符*表示signal的返回值為指標,現在跳出大括號發現字尾為函式呼叫操作符,那麼返回的指標指向的函式型別為int,現在又跳轉到最前面,發現為void。

所以,signal函式是引數型別分別為 int, 指向引數型別為int,無返回值的函式指標型別,返回值為指向int,無返回值的函式指標

閱讀至此,恭喜你衝破了指標初階的種種複雜纏繞,這些看上去令人生畏的**並不是為了酷炫而選擇層層相繞,而是為了讓我們更好的理解指標,理解c語言的宣告格式,只要心中有自行車和摩托等交通工具的構架,這些都難不住我們

當然,我們為了避免這樣令人生畏的複雜纏繞**應使用typedef簡化它:

typedef是在計算機程式語言中用來為複雜的宣告定義簡單的別名,使用它可以將「有多個組成的交通工具(複雜的型別符)」打包,從而使**便於閱讀,簡化**。

void (*signal(int,void(*)(int))(int);

code:

typedef void (*handler)(int);//注意,此處定義的名字應符合型別格式

handler signal(int,handler);//末尾處的handler即void(*)(int)型別符

指標陣列和陣列指標

有關陣列指標和指標陣列容易混淆,本文舉例說明兩者的區別,並加以分析。基本概念 指標 inta 1 int p a 指標的指標 int p2p p 簡單陣列 intb 20 指標陣列 int p 10 指標陣列,含有10個指標元素,即每乙個元素都是乙個指標 陣列指標 int p 10 這個指標用來指向...

指標陣列和陣列指標

理解這兩個概念,當從語言學的語法角度開始,定語 名詞,即 的 語句。指標陣列 指標的陣列 陣列指標 陣列的指標。一 指標陣列 元素為指標的陣列 顧名思義,就是說的首先是乙個陣列吧,然後陣列的元素是指標而已。說明形式為 type pointer array constant1 constant2 co...

指標陣列和陣列指標

該文時自己對指標陣列用法的一點總結,還望高手指點不足原文如下 由於以前對指標陣列不太明白,所以自己寫了 乙個小的測試程式來驗證了自己的猜測,先總結如下 指標陣列,由名字就可以知道的該陣列中的成員都是為指標的。其定義的方法為 char p 5 該初定義乙個包含5個char 型別的陣列的指標,由於p本身...