手繪知識點——數組指針

各位老鐵國慶節過的可還好,前天看了大閱兵,很激動,國富民強,我等也應該感到自豪~

來到指針系列第四篇,我們聊聊數組指針,即指向數組的指針。那您可能會問了,這東西有啥好說的,前邊不都提了嘛,最多就是指針的加加減減,取個元素值啥的,其他也沒什麼可說的啊。哎(二聲),事實勝於雄辯,咱們還是走一波~

首先大家應該回顧一下數組是個啥東西,按照官方的說法數組是一系列具有相同類型的數據的集合,劃重點,一系列----相同類型,我們需要注意的是數組元素在內存中是連續存放的,區別於咱們前邊提到的那些連續定義的變量,他們中間還有一些輔助的其他變量,而數組各個數組元素之間是緊密相連的,另外就是同一數組內所有元素的類型都是一樣的,這樣便於管理和各種操作。

爲了精簡文本就直接上代碼吧,前兩篇的博文文字太多,我自己看着都眼暈,這次我們儘量長話短話且說的直白接地氣:

#include <stdio.h>

int main(){
	int arr[] = { 1, 10, 23, 101, 298, 376 };
	int *a = arr;
	int len = sizeof(arr) / sizeof(arr[0]);	
	for (int i = 0; i<len; i++) {
		printf("%d  ", arr[i]);
		printf("%d  ", a[i]);
		printf("%d  ", *(arr + i));
		printf("%d  ", *(a + i));
		printf("%#x\n", arr + i);
	}
	printf("%#x,%#x,%#x,%#x\n", arr, a, &arr[0], &arr);
	printf("%#x,%#x\n", arr + 1, &arr + 1);
	printf("\n");
	return 0;
}

我們定義了一個整型數組arr,並初始化了六個值,然後定義了數組指針a,它和arr一樣都指向數組的第一個元素,即“1”。(這裏大家注意數組名arr嚴格來說並不是指針,它是一個常量,其值爲數組首元素的地址,所以數組名是不能進行++和--的,這裏我我們爲了方便暫且認爲數組名就是一個指針,如果大家感興趣可以去論壇搜一下這塊,討論的還是很激烈的);

接着往後的sizeof(arr)得到的是數組arr佔據的內存大小,即整個數組所有元素共佔有多少字節,而sizeof(arr[0])得到的是一個數組元素佔據的內存大小,二者的商即數組的元素個數(這裏我嘗試用了strlen(),結果爲1,這一點後續談論字符串時再細聊);

再往後就是一系列的輸出了,我們先看一下結果:

在內存中的具體存儲如下圖所示:

由結果可知,我們輸出數組元素可以使用下標,如arr[0]、a[0],也可以使用指針,如*(arr+1)、*(a+1),他們輸出的結果是一樣的

另外一點就是倒數第二行的輸出,四個值都是一樣的,大家再看代碼中的四個輸出值,前三個arr , a , &arr[0]很好理解,都指向數組首元素,那最後一個&arr怎麼也是這個值呢,大家都知道,如果arr是指針的話,那取其地址所得到就應該是二級指針(這個我們後邊會細聊 , 可以理解爲指向指針的指針),但輸出結果告訴我們,這並非是一個二級指針,二者指向的都是數組首元素,那它倆有啥區別呢?

來看最後一行的輸出,我們分別讓這哥倆(從形態上來看應該是父子倆)分別往後走一步,看看邁出的步伐是否整齊,結果顯而易見,二者腿並不一樣長,一個走了四個字節,指向了下一個數組元素,另一個直接一步跨出了整個數組,並且從地址來看恰巧是數組末尾元素的下一個位置(如手工畫圖所示),到這裏大家應該就明白了,arr+1相當於從數組首元素開始前進一個數組元素大小的距離,而&arr+1則從數組首元素開始前進一個數組大小的距離,可以簡單理解成 : 前者的arr代表數組首元素的地址,後者的&arr代表整個數組的地址(還可以這麼想 , 我們都知道arr是常量 , 那麼它就不能取地址了 , 既然可以輸出&arr並沒有報錯 , 那麼此時的arr已經不是之前的arr了 , 這是典型的一詞多義啊),咋樣,是不是已經凌亂了,有沒有一種自由飛翔的感覺~~~

還有比較重要的一個易混點就是數組指針的取值和自增自減的聯合運用,我們輸出一下數組指針a的幾個值:

printf("%d\n", *a);
printf("%d,%d,%d,%d,%d\n", *a,*a++, *++a, (*a)++, ++*a);

大家可以先自己算一下,你們認爲正確的輸出應該是怎樣的~~~

看結果:

如何,是不是和你們算得不一樣……這一點大家不要糾結了,我的結果也和它不一樣 , 這一塊我查了很多資料,百思不得其解,很多人都說printf函數的操作原理是從右向左計算,然後從左向右輸出,按無論怎能來都不能解釋這個結果,最後在論壇看到一位朋友的解釋,感覺很有道理,直接截圖了:

綜上也就是說罪魁禍首就是編譯器,它們的解析不盡相同,從而導致輸出結果的不同。。。

最後再說幾點吧:

1.我們定義數組指針是爲了方便對數組元素進行一系類操作,畢竟數組名是個常量,沒有變量來的方便;

2.計算數組大小時不可用sizeof(a),我們之前說過sizeof(xx)得到的是xx本身的大小,與其指向的類型是沒有關係的,那這個結果就不準確了(一般指針都佔據4字節大小)

3.我們定義數組指針時可以直接這樣定義:int   arr[]={XXX,XXX},*a=arr ; 這樣避免犯之前的錯誤,使得數組指針指向的類型與數組元素類型不一致(如int   arr[]={XXX,XXX} ;    double  *a=arr ;)

4.上邊提到的sizeof , ++ 和*都是操作符 , 瞭解其優先級有助於對具體操作的理解 , 也爲後續的討論打下堅實的基礎 :

如果本篇內容對你有一點點幫助,請點個贊或者收藏關注一下,讓我們一起努力

——————————————————   分割線   —————————————————————

2019.10.14更新

最近幾篇手繪知識點--指針系列文章閱讀量差異較大,比如第二篇耗費大量精力最終木有過百,心涼啊。。。

剛創建了一個公衆號,一開始的文章是和csdn博客同步的,後續會着重來做這一塊,比如發佈第一手信息,抽個獎啥的,希望各位小夥伴支持一下,加個關注,如果能幫忙宣傳一下就更完美了,愛你們,還是那句話,讓我們一起努力,共同進步~

公衆號爲“非著名IT表演藝術家”,比較中二的名字,就是靈光一閃,然後這個名字就冒出來了……

大家也可以掃碼關注,拜託了:

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