通過空間的標識符來處理該空間數(shù)據(jù)的方式稱為直接引用。處理簡單的數(shù)據(jù)時,直接引用的形式簡單、容易實現(xiàn),但用來處理大量數(shù)據(jù)卻不簡單。例如,存儲1萬個整數(shù)需要1萬個名稱,傳遞1萬個數(shù)據(jù)需要1萬次賦值,這都是既繁瑣又低效的操作。而且1萬個整數(shù)一般還會是一個序列,數(shù)據(jù)之間具有邏輯上的前后順序,那么按邏輯上的順序去處理這些數(shù)據(jù)就需要先按邏輯的順序存儲這些數(shù)據(jù)。既要表示數(shù)據(jù),又要表示數(shù)據(jù)之間的關(guān)系,這是直接引用方式難以實現(xiàn)的。
為了解決這個問題,我們參考機器語言中的要素——地址。機器指令由操作碼和操作數(shù)組成,操作數(shù)一般是數(shù)據(jù)的地址。在機器語言程序中,地址是處理和數(shù)據(jù)之間的媒介。在機器語言程序設(shè)計中,一個重要的步驟是為數(shù)組安排空間,以確定它們的地址。空間相鄰,地址就容易計算。按照這種邏輯可以得出一個很自然的設(shè)計方案:一組類型相同、邏輯上具有前后關(guān)系的數(shù)據(jù)存儲在一組前后相鄰的空間,這樣可以通過一個數(shù)據(jù)的地址簡單地計算出其余數(shù)據(jù)空間的地址,然后通過空間地址(而不是名稱)去處理數(shù)據(jù),我們稱這種訪問方式為間接引用。
要實現(xiàn)這種設(shè)計,就需要把這組相鄰的數(shù)據(jù)空間作為一個整體以及相應(yīng)的地址都引入C語言類型。
1指針常量
1.1指針的類型
變量的名稱經(jīng)過編譯之后就在系統(tǒng)內(nèi)部“消失”了,留下了地址和類型,地址是該變量空間的起始地址,類型是該變量的類型(見圖1中的表)。類型將指示編譯器怎樣操作特定地址上的內(nèi)存區(qū)域:該區(qū)域包含多少連續(xù)的字節(jié),數(shù)據(jù)存儲的格式,以及可以實施哪些基本操作,我們把這個類型稱為地址的基類型。通過地址來操作數(shù)據(jù)空間的方式稱為間接引用。以表1為例,地址0x12ff78的基類型為整型,通過該地址去間接引用時,系統(tǒng)將連續(xù)4個字節(jié)0x12ff78 ~0x12ff7b當作整型變量空間。地址0x12ff70的基類型是雙浮點型,編譯器將0x12ff70~0x12ff77的8個字節(jié)視為雙浮點型空間。
同樣的地址,由于地址的基類型不同,編譯器對該地址上的空間的解釋也不同,或者說編譯器將其看作不同類型的數(shù)據(jù)空間。例如,上面的地址0x12ff78,如果地址的基類型是單浮點型,那么間接引用的結(jié)果是,0x12ff78 ~0x12ff7b為單浮點型空間。
為了實現(xiàn)我們的設(shè)計,需要首先把地址這個硬件操作機制中的數(shù)據(jù)引入C語言。而在C語言中,數(shù)據(jù)要有類型。類型是數(shù)據(jù)的“身份”,決定著數(shù)據(jù)存儲空間的大小、存儲格式和對數(shù)據(jù)可以實施的基本操作。從存儲空間的大小和存儲格式來說,地址相當于無符號整型數(shù),即按無符號整型格式存儲,而且在32位操作系統(tǒng)中需要占用4個字節(jié)。但是地址的操作與無符號整型數(shù)的不同,它與間接引用的數(shù)據(jù)有關(guān),因此,為把地址這個數(shù)據(jù)引入C,需要為它定義新類型。新類型應(yīng)該具有什么樣的標識符?這就要分析地址的特點。地址關(guān)聯(lián)著兩個存儲空間,以圖1的地址0x12ff7c為例:一個是地址本身作為常量存儲的空間;另一個是通過該地址間接引用的數(shù)據(jù)空間,即我們形象地用箭頭指向的整型變量n的空間。根據(jù)這個處理特點,把地址本身的類型稱為指針類型或指針型,指針指向的數(shù)據(jù)的類型稱為指針的數(shù)據(jù)類型或指針型的基類型或指針的基類型。因此,指針是一個復(fù)合類型。
圖1 變量與地址
當我們說一個指針是某種類型或某種類型的指針,指的是該指針的基類型,或該指針指向的數(shù)據(jù)的類型。例如一個指針是整型的,或一個整型指針,是指該指針的基類型是整型的,或指針指向的數(shù)據(jù)是整型的。
指針是一個復(fù)合類型,因此它的標識符也是復(fù)合的,由表示指針類型的符號*和表示指針基類型的符號聯(lián)合組成。例如,整型指針用int*表示,雙浮點型指針用double*表示。*代表指針類型,int或double表示指針的基類型。例如圖1的地址0x12ff78,地址的基類型為整型,被引入C語言之后,用字面值常量來表示便是(int*)0x12ff78,我們稱之為指針型字面值常量或指針字面值常量。
1.2指針的基本操作
現(xiàn)在我們需要把地址的間接引用操作引入C語言作為指針型的基本操作:在指針前加間接引用運算符,也稱解引用運算符*,所得表達式作為該指針指向的空間的標識符,這種由指針運算構(gòu)成的數(shù)據(jù)空間表達式稱為間接引用表達式或解引用表達式。圖1的表代表了下面的等價式:
x=*(double*)0x12ff70
m=*(int*)0x12ff78
n=*(int*)0x12ff7c
我們可以做個實驗來證實這個等價式。首先通過輸出語句確定變量的地址:
printf(\"%x,%x,%x\\",n,m,x);//輸出變量n、m和x的地址
假設(shè)輸出結(jié)果是12ff7c,12ff78,12ff70
(如果不是,那么以輸出的結(jié)果為準)。然后通過指針常量間接修改變量n、m和x的值:
*(int*)0x12ff7c=5;//相當于n=5;
*(int*)0x12ff78=*(int*)0x12ff7c;//相當于m=n;
*(double*)0x12ff70=3.1415;//相當于x=3.1415;
printf(\"n=%d,m=%d,x=%f\\",n,m,x);//輸出變量n、m和x的值,檢驗結(jié)果
在我們的設(shè)計方案中,由一個數(shù)據(jù)空間地址計算出其余的數(shù)據(jù)空間地址是主要的操作,現(xiàn)在我們將它設(shè)計為指針類型的基本操作:指針加減一個整數(shù)。假設(shè)一組雙浮點型數(shù)5.5、6.6、7.7、8.8、9.9,它們的存儲空間按地址從小到大依次相鄰,地址依次為0x120000、0x120008、0x120010、0x120018、0x120020,用指針字面值常量來表示便是(int*)0x120000、(int*)0x120008、(int*)0x120010、(int*)0x120018、(int*)0x120020。如果用指針加減一個整數(shù)的基本運算來表示,那么指向5.5的存儲空間的指針(int*)0x120000加1應(yīng)該是指向6.6的存儲空間的指針(int*)0x120008,加2應(yīng)該是指向7.7的存儲空間的指針(int*)0x120010,依次類推(見圖2)。反過來,指向9.9的存儲空間的指針(int*)0x120020減1應(yīng)該是指向8.8的存儲空間的指針(int*)0x120018,減2應(yīng)該是指向7.7的存儲空間的指針(int*)0x120010,依次類推。
概括地說,一個指針加上(或減去)一個整數(shù)所得到的指針,其地址會增加(或減少)指針基類型大小(字節(jié)數(shù))的該整數(shù)倍,即指針的算術(shù)運算單位是該指針基類型的大小,或者說是指針指向的數(shù)據(jù)類型的大小。
圖2 指針算術(shù)運算
對指針做加減整數(shù)的運算是沒有限制的,但是對指針間接引用的空間是有限制的,它必須是系統(tǒng)分配的、可以由指針間接引用的空間,否則就可能破壞系統(tǒng)空間的數(shù)據(jù)。這個限制使我們不能隨便使用一個指針字面值常量進行間接引用運算。例如下面的語句:
*(int*)0x12ff7c=6;
只有在0x12ff7c確是一個已經(jīng)定義的整型數(shù)據(jù)空間地址的時候才是合理的。
取址運算實質(zhì)上是指針的基本操作。例如,有下面的等價式:
x=*(double*)0x12ff70
對上面的等價式左右實施取址運算,有等價式:
x=*(double*)0x12ff70=(double*)0x12ff70
對上面的等價式左右實施間接引用運算*,有等價式:
*x=*(double*)0x12ff70=x
上面的等式說明取址運算和間接引用運算*互為逆運算。
指針的值是無符號整型數(shù),可以實施邏輯運算和關(guān)系運算。
綜上所述,間接引用*、取址、加減一個整數(shù)、兩個指針相減、關(guān)系運算和邏輯運算是指針的基本操作。
兩個指針能夠相加或相乘嗎?不行,因為它無意義。一種類型應(yīng)該包含哪些基本操作,這取決于我們設(shè)計這種數(shù)據(jù)類型的目的或用途。
2數(shù)組類型
我們的設(shè)計是,一組類型相同、邏輯上有前后關(guān)系的數(shù)據(jù),存儲在物理上前后相鄰的變量空間,使得通過一個數(shù)據(jù)空間的地址可以計算出其余的數(shù)據(jù)空間地址,然后通過空間地址(而不是空間名稱)去間接訪問數(shù)據(jù)(空間)。前面介紹過把地址作為指針引入C語言,現(xiàn)在我們把物理上前后相鄰的一組變量作為一個整體引入C語言。我們把這個整體稱為數(shù)組類型變量,簡稱數(shù)組,把每一個作為成員的變量稱為數(shù)組元素,數(shù)組元素空間按地址從小到大依次相鄰。數(shù)組元素的個數(shù)稱為數(shù)組長度或容量。
根據(jù)我們的設(shè)計,對數(shù)組元素的引用是間接的,這需要知道指向第一個數(shù)組元素的指針。而編譯器對空間的分配是隨條件變化的,指向第一個數(shù)組元素的指針不能是字面值常量,只能是符號指針常量,即用符號表示的指針常量,這個符號由數(shù)組名兼任,稱為(一維)數(shù)組指針,數(shù)組元素類型就是數(shù)組指針的基類型。
數(shù)組名既是數(shù)組變量的標識符,又是指向第一個數(shù)組元素的指針常量,具體代表什么要根據(jù)上下文來確定。
定義一個數(shù)組需要指出數(shù)組名、數(shù)組長度和數(shù)組元素類型(數(shù)組指針基類型)。數(shù)組的定義格式為:
類型標識符數(shù)組名[整型常量表達式];
其中類型標識符表示數(shù)組元素類型,整型常量表達式表示數(shù)組長度即容量。數(shù)組類型沒有獨立的標識符,因為數(shù)組實際上是一個復(fù)合類型,數(shù)組的存儲格式、存儲空間大小和基本操作由其數(shù)組元素類型和數(shù)組長度決定,所以數(shù)組類型由數(shù)組元素類型和數(shù)組長度聯(lián)合表示。當我們說某種類型的數(shù)組或數(shù)組是某種類型時,是指該數(shù)組的數(shù)組元素是某種類型的。例如,定義一個長度為5、數(shù)組名是d、數(shù)組元素類型為雙浮點型的數(shù)組,即長度為5、數(shù)組名是d的雙浮點型數(shù)組:
double d[5];
//長度為5,數(shù)組名是d的雙浮點型數(shù)組
數(shù)組名d既表示數(shù)組(變量),又表示指向第一個數(shù)組元素的指針常量,具體表示什么呢?若實施sizeof運算,則d代表數(shù)組,結(jié)果是:
sizeof(d)=5*sizeof(double)=5*8=40
//5個數(shù)組元素空間大小之和
還可以由表達式sizeof(d)/sizeof(do-
uble)計算出整型數(shù)組d的容量即長度。
若實施算術(shù)運算和間接引用運算,則d代表數(shù)組指針。根據(jù)指針的性質(zhì),d,d+1,d+2,d+3,d+4依次是指向第1至第5個數(shù)組元素的指針,實施間接引用運算之后,*d,*(d+1),*(d+2),*(d+3),*(d+4)依次是第1至第5個數(shù)組元素的間接引用表達式。不過,一般采用符合數(shù)學(xué)習(xí)慣的下標表達式或索引表達式:d[0],d[1],d[2],d[3],d[4],其中“[]”是下標運算符或索引運算符,其中的整數(shù)稱為數(shù)組元素下標或索引。數(shù)組元素的間接運算表達式和下標表達式是一回事(見圖3)。
圖3 數(shù)組的綜合特征
長度為n的數(shù)組,下標為0~n-1,超過下標范圍的索引訪問是非法的,不管編譯器對超越下標范圍的訪問如何處理,我們都要自覺地遵守這個實際上屬于我們自己的設(shè)計。例如,對上面定義的數(shù)組d,下標表達式d[5]和d[-2]是非法的。這不是一種規(guī)定,而是數(shù)組和數(shù)組指針作為一個整體的表現(xiàn):數(shù)組元素沒有名稱,它要由數(shù)組指針間接引用,它的索引訪問或下標訪問的實質(zhì)就是數(shù)組指針的間接引用運算(例如d[2]=*(d+2)),這是數(shù)組對數(shù)組指針的依賴;而數(shù)組指針是其間接引用范圍由數(shù)組范圍決定的指針。
一個變量可以看作是長度為1的數(shù)組。例如:
int n=5;
n等價于長度為1的整型數(shù)組指針,因此(n)[0]與n等價:
(n)[0]=*(n)=*n=n
數(shù)組是一個復(fù)合類型(見圖3),包含數(shù)組類型、數(shù)組指針類型和數(shù)組元素類型。數(shù)組的類型由數(shù)組元素的類型和數(shù)組長度復(fù)合表示,例如長度為5的雙浮點型數(shù)組的類型是double[5]。數(shù)組指針的基類型是數(shù)組元素類型,數(shù)組指針的間接引用運算只有在該數(shù)組范圍內(nèi)實施才有意義,這是指針對數(shù)組的依賴,而數(shù)組的元素沒有名稱,對數(shù)組元素的引用依賴指針,這是數(shù)組對指針的依賴。數(shù)組指針和數(shù)組共用一個名稱隱含了這種整體關(guān)系。d作為數(shù)組指針和d的值相同,但它們不是同一類型的指針,d等價于d[0],其基類型等價于數(shù)組元素d[0]的類型double,所以數(shù)組指針d的類型double*,算術(shù)運算單位是8,而d的基類型是數(shù)組d的類型doulbe[5],所以d的類型是doulbe(*)[5],運算單位是40。
3 指針變量
數(shù)組元素沒有名稱,只能依賴數(shù)組指針的間接引用。數(shù)組指針是打開數(shù)組元素空間的“鑰匙”。如果把數(shù)組指針傳給同類型的指針變量,那么該指針變量就可以和數(shù)組指針“共享”一個數(shù)組空間,我們稱此為地址傳遞。一個指針,不論什么類型,在32位機上都只占4個字節(jié),所以復(fù)制數(shù)組指針比復(fù)制數(shù)組中的數(shù)據(jù)更有效率。指針變量的定義格式為:
類型標識符* 變量名;
以圖4為例,把數(shù)組指針a賦給指針變量p,就有了等價式:
p[i]=a[i]
但是,指針變量p與數(shù)組指針a不等價,因為前者是指針變量,后者是指針常量。指針變量p與數(shù)組a也不等價,下面的等式可以說明:
sizeof(p)=4 //指針變量空間大小
sizeof(a)=20//數(shù)組空間大小
而且指針p與a值不同,基類型也不同,p是p空間地址,是指向指針空間p的指針,類型是int**,而a是數(shù)組空間地址,是指向數(shù)組空間的指針,類型是int(*)[5]。
因為數(shù)組名稱既表示數(shù)組指針又表示數(shù)組,所以要從數(shù)組名稱中取出數(shù)組指針賦給指針變量,就需要隱式類型轉(zhuǎn)換,通常稱之為decay。
圖4 指針變量
如果傳遞數(shù)組指針的目的是傳遞數(shù)組的值,那么應(yīng)該把數(shù)組指針傳遞給同類型指針變量。例如,整型數(shù)組指針應(yīng)該傳給整型指針變量,雙浮點型數(shù)組指針應(yīng)該傳給雙浮點型指針變量。下面我們以反例來說明這樣做的意義。
int a[5]={10,15,20,25,30};
//整型數(shù)組
double* pd;
//雙浮點型指針變量
pd=(double*)a;
//整型數(shù)組指針經(jīng)強制轉(zhuǎn)換之后賦給雙浮點型指針變量
在32位機上,雙浮點型指針pd的算術(shù)運算單位是8個字節(jié),而整型指針常量a的運算單位是4個字節(jié),因此,pd+i的值和a+i的值不等,從而pd[i]和a[i]也不等。又例:
int a[5]={ 10,15,20,25,30};
//整型數(shù)組
float* pf;
//單浮點型指針變量
pf=(float*)a;
//整型數(shù)組指針經(jīng)強制轉(zhuǎn)換后賦給單浮點型指針變量
在32位機上,單浮點型指針pf的算術(shù)運算單位是4個字節(jié),整型指針常量a的運算單位也是4個字節(jié),因此,pf+i的值和a+i的值相等,但是編譯器對它們所指向的數(shù)據(jù)類型解釋不同:pf[i]是單浮點型,a[i]是整型。具體地說,a[0]以普通整型格式存儲著10,而pf[0]按單浮點型格式“解讀”時,其中存儲的不是10;而且對a[0]可以實施求余運算,對pf[0]不能實施該運算。
如果傳遞數(shù)組指針的目的是“讓出”數(shù)據(jù)處理之后而“空閑下來”的數(shù)組空間,那么可以把該數(shù)組指針傳遞給不同類型的指針變量,但是需要強制類型轉(zhuǎn)換。以圖5為例,把長度為2的雙符點型數(shù)組指針d傳遞給整型指針變量pi,通過pi可以訪問長度為4的整型數(shù)組空間(按類型大小計算,長度為2的雙浮點型數(shù)組空間可以用做長度為4的整型數(shù)組空間)。雙浮點型數(shù)組指針d和整型指針變量pi都指向同一個空間,我們用哪一種類型的指針去間接引用,這個空間就是哪一種類型的數(shù)組空間,而且空間中的數(shù)據(jù)是最后存儲的數(shù)據(jù)。例如,在語句int *pi=(int*)d執(zhí)行之后,pi[0]=17執(zhí)行之前,雖然指針d和pi都指向一個空間,但是d[0]和d[1]中的雙浮點型數(shù)2.125和3.625還存在,執(zhí)行了語句pi[0]=17和pi[1]=29以后,d[0]中的雙浮點型數(shù)2.125已經(jīng)不存在,改為兩個整型數(shù)17和29,但是d[1]的值3.625還存在。
圖5 由不同類型數(shù)據(jù)共享的數(shù)組空間
一個變量可以看作是一個長度為1的數(shù)組,因此指向變量的指針可以看作是指向長度為1的數(shù)組的指針(見圖6)。
pn[0]=*pn =(n)[0] =n
圖6 指向變量的指針
4二維數(shù)組類型
一個序列存儲在一維數(shù)組中,其元素在邏輯上的前后位置由數(shù)組元素的下標來表示??墒侨绾未鎯σ粋€矩陣呢?矩陣的元素在邏輯上有兩個位置,行的前后位置和列的前后位置。為此需要引入二維數(shù)組。
二維數(shù)組是數(shù)組元素為一維數(shù)組(稱行一維數(shù)組)的一維數(shù)組。因為一維數(shù)組的元素類型是相同的,所以一個二維數(shù)組的行一維數(shù)組的類型相同,長度相同,元素的類型也相同。行一維數(shù)組的個數(shù)稱為二維數(shù)組的行數(shù),行一維數(shù)組的長度稱為二維數(shù)組的列數(shù)。行一維數(shù)組也稱為二維數(shù)組行元素,行一維數(shù)組元素也稱二維數(shù)組元素。二維數(shù)組定義格式為:
類型標識符數(shù)組名[行數(shù)][列數(shù)];
例如,定義一個4行3列的二維整型數(shù)組:
int a[4][3];
二維數(shù)組作為特殊的一維數(shù)組,數(shù)組長度為4,其數(shù)組元素為:
a[0],a[1],a[2],a[3]
它們分別是長度為3的行一維整型數(shù)組,類型都是int[3]。行一維數(shù)組的元素的類型是整型,而且依次為:
a[0][0]a[0][1]a[0][2]
//行一維數(shù)組a[0]的數(shù)組元素
a[1][0]a[1][1]a[1][2]
//行一維數(shù)組a[1]的數(shù)組元素
a[2][0]a[2][1]a[2][2]
//行一維數(shù)組a[2]的數(shù)組元素
a[3][0]a[3][1]a[3][2]
//行一維數(shù)組a[3]的數(shù)組元素
與一維數(shù)組類似,作為特殊的一維數(shù)組,數(shù)組名a既表示數(shù)組(用斜體a表示以示區(qū)別),又表示數(shù)組指針。當a表示數(shù)組時,它的類型是由元素類型即行一維數(shù)組類型int[3]和數(shù)組長度即行數(shù)也即行一維數(shù)組個數(shù)4聯(lián)合構(gòu)成,int[4][3]。而且
sizeof(a)=∑sizeof(a[i]) =4*12=48
當a表述數(shù)組指針時,有等式:
a=a[0]
a[0]作為行一維數(shù)組表達式,既表示行一維數(shù)組類型(用斜體a[0]表示以示區(qū)別),又表示行一維數(shù)組指針。在上面等式的取址運算a[0]中,a[0]表示行一維數(shù)組,因此指針a的基類型是行一維數(shù)組類型int[3],算術(shù)運算單位是12,即一個行一維數(shù)組大小,有等式
a+i=a[i](i=0~3)
因此被稱為二維數(shù)組指針,類型用int (*)[3]表示。二維數(shù)組a的其他綜合特性見表1和圖7
圖7二維整型數(shù)組a[4][3](陰影部分表示指針常量)
一個長度為n的一維數(shù)組可以看作是1行n列二維數(shù)組。例如:
double d[5]={1,2,3,4,5};
d相當于1行5列二維雙浮點型數(shù)組指針(見圖8)。
反之,一個m行n列二維數(shù)組可以看作長度為m*n的一維數(shù)組。
圖8長度為5的一維數(shù)組d可以看作1行5列二維數(shù)組
5二維指針變量
與二維數(shù)組指針常量對應(yīng)的是二維指針變量,定義格式為:
類型指示符 (*指針變量名)[列數(shù)];
舉例說明:
int (*p)[3];
//二維指針變量p
int a[4][3]={{1,2,3},{4,5,6},{7,8,9},{10,
11,12}};
//二維整型數(shù)組
p=a;
//二維數(shù)組指針傳遞
這時的二維指針變量p等價于二維數(shù)組指針a:
p+i=a+i(i=0,1,2,3)
p[i]=a[i](i=0,1,2,3)
p[i][j]=a[i][j](i=0,1,2,3,j=0,1,2)
但是不等價于二維數(shù)組a:下面的等式可以說明:
sizeof(p)=4//p表示指針變量
sizeof(a)=48//a表示二維數(shù)組
圖9 二維指針變量和二維數(shù)組
6二維數(shù)組和(一維)指針
一個m行n列二維數(shù)組,可以看作是長度為m*n的一維數(shù)組。例如:
int a[4][3]={{1,2,3},{4,5,6},{7,8,9},
{10,11,12}};
a[0]是指向行一維數(shù)組元素a[0][0]的指針常量,它等價于長度為12的一維整型數(shù)組指針,該一維數(shù)組的12個元素依次為:
a[0][0]a[0][1]a[0][2]
a[0][3]a[0][4]a[0][5]
a[0][6]a[0][7]a[0][8]
a[0][9]a[0][10]a[0][11]
二維數(shù)組指針a的行下標(假設(shè)用i表示)增加1,地址值增加12,一維數(shù)組指針a[0]的下標增加1,地址值4,于是有等式:
a[0][i*3+j]=a[i][j]
于是,可以把二維數(shù)組的行一維數(shù)組的地址傳給(一維)指針變量:
int*p=a[0];//int *p=*a; 或int *p=a[0][0];
于是有等式((見圖10)):
p[i*3+j]=a[0][i*3+j]=a[i][j]
圖10 二維數(shù)組和(一維)指針變量
7指針數(shù)組和指針的指針
所謂一維指針數(shù)組,就是數(shù)組元素為(一維)指針變量的一維數(shù)組。例如:
char* a[5];
a是長度為5的字符型指針數(shù)組,數(shù)組元素a[0]、a[1]、a[2]、a[3]、a[4]都是字符型指針變量,它們各自可以指向一維字符數(shù)組,特別是字符串:
a[0]=\"File\";a[1]=\"Edit\";
a[2]=\"Compile\";a[3]=\"Run\";
a[4]=\"Tools\";
指針數(shù)組可以初始化:
char* a[5]={\"File\",\"Edit\",\"Compile\",
\"Run\",\"Tools\"};
或
char* a[]={\"File\",\"Edit\",\"Compile\",
\"Run\",\"Tools\"};
數(shù)組指針a類型應(yīng)該由“*”和其基類型即數(shù)組元素char*聯(lián)合構(gòu)成,所以是char**,被稱為指針的指針常量:
char** pa;//指針的指針變量
pa=a;//接受字符型指針數(shù)組的指針a的值(見圖11)
或
char** pa=a;
圖11 字符指針數(shù)組和字符指針的指針
二維數(shù)組是數(shù)組元素為指針常量的指針數(shù)組,反之,指針數(shù)組是行一維數(shù)組是指針變量的二維數(shù)組。它們在下面的情形下統(tǒng)一。假設(shè)
int a[4][3];//二維數(shù)組
int* p[4];//指針數(shù)組
令指針數(shù)組的指針元素分別指向二維數(shù)組的行一維數(shù)組
p[0]=a[0];
p[1]=a[1];
p[2]=a[2];
p[3]=a[3];
則有等式:
p[i][j]=a[i][j]
8小結(jié)
機器語言發(fā)展到C語言,作為機器語言要素的地址就要發(fā)展為C語言的要素,這就是指針類型。指針是C的類型,就應(yīng)該和整型、字符型等語言內(nèi)置類型一樣,具有自己的常量,因此,指針字面值常量的引入是不可避免的。而處理的需要又使指針一出現(xiàn),就和數(shù)組構(gòu)成一個整體,它們都以對方的存在作為自己存在的前提:指針的基類型是它可以指向的數(shù)組的元素類型,指針間接引用范圍取決于它實際指向的數(shù)組大??;一個指針常量就是一個數(shù)組指針;一個指針變量,當它指向一個數(shù)組時,與該數(shù)組指針等價。這是指針對數(shù)組的依賴。反之,數(shù)組的元素沒有名稱,它的表示依賴指針;數(shù)組指針是指向該數(shù)組的指針常量。這是數(shù)組對指針的依賴。一個變量等價于一個長度為1的數(shù)組,指向一個變量的指針看作是指向一個長度為1的數(shù)組的指針,這實際上依然是指針和數(shù)組的相互依賴、相互作用的整體性關(guān)系。但是這還不能證明指針和數(shù)組定義是科學(xué)的,還需要通過二維指針和二維數(shù)組的定義來檢驗。例如,二維數(shù)組必須是一維數(shù)組的推廣,就像二重積分是一重積分的推廣一樣,而且它們在一定條件下可以互相轉(zhuǎn)化,例如,長度為n的一維數(shù)組等價于1行n列的二維數(shù)組,m行n列的二維數(shù)組等價于長度為m*n的一維數(shù)組。