【C語言】【數組指針】和【指針數組】都是啥跟啥?

        相信學習過C語言的童鞋,一定被這2個東西折騰過吧?究竟它們都是何方神聖呢?帶着這個問題,筆者想通過本文給你一個清晰的答案。通過閱讀本文,你將瞭解到以下內容:

  • 什麼是數組指針?
  • 什麼是指針數組?
  • 數組指針和指針數組有什麼區別?
  • 使用指針數組的注意事項

什麼是數組指針?


        【數組指針】,從字面意思上理解,就是一個【指針】;“數組”只是起到了修飾“指針”的作用,所以連起來的意思就是【指向數組的指針】。這一點與上一篇文章介紹 【函數指針】有異曲同工的含義。

        從C語言的語法上理解,數組指針的表示形式爲:

//定義一個一維數組
int a[3];

//定義一個指針,指向一維數組的首地址
int *q = a;

//定義一個3行4列的二維數組
int b[3][4]; 

//定義一個數組指針,它指向二維數組的首地址
int (*p)[4] = b;

        從數組指針的形式上看,因爲()運算符擁有最高優先級,所以整個語句優先被解釋成一個指針;接着,這個指針再指向另一個數組的首地址,[x]接上該數組的列數,即得到如上的數組指針的定義。

        經過這個例子,我們可以看到,數組指針一般用於表達多維數組,對比起多維數組的表示,採用數組指針的形式可以在一定程度上理解難度減小了。比如,有了如上的數組指針定義後,這裏b是個二維數組的數組名,相當於一個二級指針常量;p是一個指針變量,它指向包含5個int元素的一維數組,此時p的增量以它所指向的一維數組長度爲單位;*(p+i)是一維數組b[i][0]的地址;*(p+2)+3表示b[2][3]地址(第一行爲0行,第一列爲0列),*(*(p+2)+3)表示b[2][3]的值。


什麼是指針數組?


        【指針數組】,從字面意思上理解,它就是一個數組,只不過“指針”是用於修飾“數組”的,所以合起來理解就是:【一個數組元素存放的是指針的數組】。

        從C語言的語法上理解,【指針數組】的定義形式如下所示:

//定義一個char *的指針數組
char *p[5];

        這裏,它表示的含義是,一個由5個元素組成的一維數組,每個數組元素都是一個指針(地址)。訪問數組的元素,我們都是採用 數組名[數組下標] 的形式訪問的,那麼【指針數組】也不例外,訪問第一個元素,則是p[0];同理,p[2]表示的是第3個指針。


數組指針和指針數組有什麼區別?


        從字面上看,確實很容易混淆兩者的概念;我們理解的時候,需要注意名詞誰先誰後。一般來說,在前面的名詞是用於修飾後面的名詞,而後面的名詞決定了整個詞組的性質。

        【數組指針】:數組修飾指針,它的本質是一個指針;一般這個指針指向一個二維數組,形式爲: int (*p)[M]。

        【指針數組】:指針修飾數組,它的本質是一個數組;這個數組裏面的元素,存放的都是指針,形式爲: int *p[M]。

        如上定義中,第一個M表示二維數組的列數,第二個M表示的指針數組(一維數組)的元素個數。

        數據訪問方面:

  • (*p)[0] 表示的是二維數組中的第一行的首地址;
  • p[0] 表示的指針數組的第一個元素,即第一個指針地址。    

使用指針數組的注意事項


        這兩個概念不但容易混淆,而且在使用過程中也是十分容易出錯,曾經筆者在【指針數組】上摘過跟頭。現將出錯的教訓分享給大家:

  • 求一個指針數組的中元素的個數,不是簡單地使用sizeof

        比如有一個指針數組的定義:

char *p[5];

        假設在編程平臺上,一個指針所佔用的地址空間是4個字節,即sizeof(char *) = 4;那麼如果使用sizeof(p)去求這個指針數組所佔用的地址空間時,求得的大小是4*5=20;而每個元素都是char *類型,所以求得指針元素的個數爲: 20 / 4 = 5。

        於是,我們得出一個公式,求指針數組的元素個數:

//直接求得指針數組p的元素個數
cnt = sizeof(p) / sizeof(p[0]);

//很多時候,我們會定義一個宏來表示,形式如下:

#ifndef ARRAY_SIZE
#define ARRAY_SIZE(a)  (sizeof(a) / sizeof(a[0]))
#endif

//使用ARRAY_SIZE宏求指針數組p的元素個數
cnt = ARRAY_SIZE(p);
  • 定義字符串類型的指針數組時,每個元素(字符串)注意用分號隔開,否則可能出現意想不到的事情

        假設有以下2個指針數組的定義:

const char *p1[] = 
{
    "12345",
    "23456",
    "34567",
    "45678",
    "56789",
};

const char *p2[] = 
{
    "12345",
    "23456"
    "34567",
    "45678"
    "56789",
};

         如果你不仔細看,你可能覺得p1和p2的定義是一致;仔細一看,原來p2中少了2個分號;而這2個分號一少,直接就導致p2的最終被編譯器識別成的定義爲:

//最終被識別的定義
const char *p2[] = 
{
    "12345",
    "2345634567",
    "4567856789",
};

        看到區別了嗎?由於分號的缺失導致前後相鄰的字符串被結合在一塊,被連接成一個更長的字符串,而這種【拼接】是編譯器自動識別完成的,它不會提示任何錯誤,因爲在它看來根本就不是錯誤。對使用者而言,這樣定義一改變,原本本應該爲5個元素的字符串數組,就變成了3個字符串的數組,這簡直就是災難啊!!!


        以上就是筆者對【數組指針】和【指針數組】的實踐,得出的切實理解,希望能夠幫助大家更近一步地理解它們。以上提及觀點,均爲筆者本人的觀點,如有紕漏之處,還望指正。感激不盡。

版權申明:本文爲博主原創文章,轉載請註明出處!https://blog.csdn.net/szullc/article/details/84900643

原創作者:李路昌

電子郵箱:[email protected]

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