C語言中的指標和陣列

2021-09-08 15:10:40 字數 3671 閱讀 4058

下面的內容節選自由我所執筆的會議記錄。對於本文的不足之處,各位可以提出自己的看法。

q1:指標和陣列到底是怎麼一回事?

a:指標和陣列有本質的不同。指標就是乙個記憶體位址,在32位系統下,乙個指標永遠佔4個位元組;陣列是一塊連續的記憶體空間,我們從乙個已定義的陣列中可以獲得陣列大小以及這塊連續記憶體空間的起始位址。這個起始位址即陣列首元素的位址,更具體的說是陣列中首個元素的首位址。

在c語言中,只有一維陣列。但是,當乙個一維陣列的元素是仍然是一維陣列時,就形成了所謂的一維陣列。如何印證這一點?二維陣列在記憶體中的儲存方式仍然是按照一維陣列那樣線性儲存的,只不過這個陣列的元素按照另乙個一維陣列線性儲存。多維陣列照此類推。

q2:我還能獲得關於陣列和指標更詳細的說明嗎?

a:當然可以。

我們通常會這樣使用乙個指標:

int a[5];

int *p=a;

我們首先定義了乙個指向int型別的指標p,在定義p的同時將其初始化為a;通常我們將這種行為稱為「p指向乙個大小為5的整形陣列a」。事實上,我們可以更具體的想一下:p真的指向整個陣列嗎?當然不是。p只是指向乙個int型變數而已。在這個例子中,p指向的是a陣列的首元素。換句話說,p儲存的是&a[0]。另外,p是變數,我們可以對p進行自加自減(在a陣列有效的範圍內),讓p指向a陣列的其他元素。換句話說,p可以儲存整個陣列中任意乙個元素的位址(更具體的是這個元素的首位址)。而陣列名a雖然也是個位址,但是它是乙個常量,它永遠儲存的是陣列的首位址,不可改變。

對於上述所言的p指標,我們可以通過指標方式*(p+i)和下標方式p[i]訪問陣列。對於陣列名a而言,我們也可以通過*(a+i)和下標方式a[i]來訪問陣列。對於p指標而言,以指標方式訪問陣列的過程是這樣的:我們通過p指標首先獲取這個陣列的首位址,然後加上i個偏移量,得到陣列中第i個元素的位址,最後通過引用,得到具體的值。而對於p[i]這種下標訪問方式,最終還是會被轉化成上述指標訪問方式。對於陣列名a而言,與p方式相同。

另外還要注意,上述所說的i個偏移量,並不是加上i個位元組那麼簡單;而是i個元素的總位元組數。因此,給指標p加上乙個整數和給指標p的二進位制表示形式加上同樣的整數,兩者的含義是截然不同的。

另外,剛說到a是乙個常量的問題,我想到了const關鍵字。上次在現代軟體工程課程上,我聽到有的同學說const所修飾的是常量。const修飾的當然是乙個變數,只不過這個變數是唯讀的,即便這個變數的特性和常量相似。

a:我們首先可以獲知以下資訊:陣列a是乙個包含有3個元素的陣列,每個陣列元素是乙個大小為4的一維陣列。因此,我們通常說這個陣列有三行四列(但是你要清楚:記憶體中並不會出現3*4的那樣的**)。具體來說,二維陣列a有以下三個元素:a[0],a[1],a[2];每乙個元素又都是乙個一維陣列。對於一維陣列a[0]來說,它又有4個元素:a[0][0],a[0][1],a[0][2],a[0][3];這4個元素是int型的。

以上就是關於這個陣列的基本結構,下面從指標的角度來分析這個陣列。

對於上述的陣列名a,我們稱為指向指標的指標(a是乙個常量)。對於一維陣列我們知道,陣列名是陣列中首元素的位址。對於上述所言的陣列a,a當然也是這個陣列首元素的位址。那麼,陣列a的首元素是什麼?對了,就是a[0]。那麼a這個指標儲存的就是a[0]的位址,即a等價於&a[0]。那麼a+i也就很明顯了:a[i]的位址。再來想a[i]是什麼?它是陣列a中第i個元素。在陣列a中,第i個元素是什麼?它是乙個大小為4的一維陣列。對應到上述所言的「三行四列」,a+i即是指向第i行的指標。可以看到,i這個偏移量此刻是以行為單位的。

我們上述已說明,a+i指向a[i],a[i]是乙個一維陣列。a+i是乙個指向指標的指標,那麼現在取出a+i的值,也就是*(a+i)。從我們所說的「指向指標的指標」來看,*(a+i)也是乙個指標,但是這個指標指向什麼?它指向陣列a[i]的首元素的位址,也就是a[i][0]的位址,即&a[i][0]。那麼陣列a[i]中第j個元素的位址是什麼?那就是*(a+i)+j,即&a[i][j]。當然,也可以這麼寫:a[i]+j。

另外要說明的是,上述的a+i和*(a+i)的記憶體位址其實是相同,但是含義是完全不同的。具體原因,你可以從上面的陳述中得到答案。

q4:難道指標就只有這麼多內容嗎?

a:當然不是。關於指標更高階的使用,還有指向一維陣列的指標;指標陣列;函式指標。可能它們的定義方式會讓你迷惑,但是,無論如何,它們本質上仍然是指標。先了解最基本的指標,然後再理解這些高階指標就簡單了許多。

上述q1~q3從某種角度來說,敘述的過於羅嗦,甚至有時候必須得咬文嚼字;並且,必須在實踐的基礎上理解上述內容。我個人的建議是,指標部分必須建立在「理論——實踐——理論」這樣反覆的過程中,否則——套用現在最fashion的話——「指標神馬的一切都是浮雲~」。

今天在看到typedef int (*int_arry)[10];這條語句時,因為對這樣的定義使用較少,就想著編寫乙個test.c來試試看。不過,當我編寫完乙個簡單的測試程式時,卻發現我對指向一維陣列的指標的使用了解甚少。

起初,我的程式是這樣:

#include  < stdio.h >

typedef int (*int_array)[10];

int main()

;

int_array i=&a;

printf("%d=%d\n",i[4],a[4]);

return 0;11

}

編譯後,提示如下錯誤:

test.c: in function 『main』:

test.c:10: warning: format 『%d』 expects type 『int』, but argument 2 has type 『int*』

也就是說,i[4]是乙個int*型的指標。為什麼會出現這樣的錯誤?既然i是乙個指向有10個整形元素陣列的指標。那麼將i指向陣列a,然後使用i[4]獲取第四個元素有什麼錯?

那我們從另乙個角度來分析,一般i[4]這樣的形式都可以看成*(i+4)這樣的形式。i+4是什麼?對了!i是乙個陣列指標,那麼i+4也就是乙個陣列指標。如果將i所指的陣列看作乙個二維表的第1行,那麼i+4就是指向第5行的指標。也就是說它相對於i所指向位置的偏移量為4*sizeof(int)*10個位元組。因此*(i+4)仍然是乙個指標,只不過它指向第5行的首個元素。

看來我們找到問題所在,i[4]並不是乙個整形元素,而是乙個指向整形元素的指標。上面程式中,我原本的意思是通過i來列印陣列a中第四個元素。那麼此刻我們應該這麼修改:

printf("%d=%d\n",i[0][4],a[4]);

或者下面任意一句:

printf("%d=%d\n",(*(i+0))[4],a[4]);

printf("%d=%d\n",*(i[0]+4),a[4]);

printf("%d=%d\n",*(*(i+0)+4),a[4]);

你會發現,如果p是乙個指向指標的指標,那麼總能夠通過兩次的*、兩次的或者一次*和一次取得這個指標最終指向的資料,因為說到底總能夠化成*的形式。理解了這些,上面的語句對你也就不成問題了。got it?

c語言中的指標和陣列

最近在複習c語言,看了c primer plus 這本書,對其中難以理解的陣列和指標有一些自己小小的體會,現記錄下來。指標和一維陣列 include int urn 5 int main void 輸出結果如下 pointer value,dereferenced pointer,pointer a...

C語言中的指標和陣列

指標和陣列關係密切。不帶下標的陣列名實際上就是指向陣列第乙個元素的指標。char p 0 以下兩句完全等價 p,p 0 換言之,也就是 p p 0 為真,因為陣列第一元素的位址也就是陣列的位址。觀察下面程式,p1和p2實際指向同乙個記憶體位址。在指向某陣列元素的指標上加或減去乙個整數,就可以指向另乙...

C語言中指標和陣列

首先,明確乙個概念,指標是什麼,一旦提到這個老生常談且富有爭議性的話題,那真是1000個人有1000種看法。在國內的很多教材中,給出的定義一般就是 指標就是位址 從初步理解指標的角度來說,這種說法是最容易理解的,但是這種說法明顯有它的缺陷所在。指標就是位址 這種說法相當於 指標 字面值位址 或者說乙...