




版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
第7章數(shù)組7.1一維數(shù)組7.2二維數(shù)組7.3數(shù)組與運(yùn)算符7.4數(shù)組與函數(shù)7.5字符數(shù)組與字符串7.6數(shù)組應(yīng)用實(shí)例
7.1一維數(shù)組
7.1.1一維數(shù)組的定義
同其他基本數(shù)據(jù)類型的變量一樣,在C語(yǔ)言中使用數(shù)組變量也遵循“先定義、后使用”的原則。
一維數(shù)組的定義方式為
類型說(shuō)明符數(shù)組名[常量表達(dá)式];
其中:
類型說(shuō)明符可以是任一種基本數(shù)據(jù)類型或構(gòu)造數(shù)據(jù)類型的說(shuō)明符。數(shù)組的類型實(shí)際上是指各個(gè)數(shù)組元素的數(shù)據(jù)類型。對(duì)于同一個(gè)數(shù)組,其所有元素的數(shù)據(jù)類型都是相同的。
數(shù)組名是用戶定義的數(shù)組標(biāo)識(shí)符,其書寫規(guī)則應(yīng)符合標(biāo)識(shí)符的書寫規(guī)定,且不能與其他變量同名。
方括號(hào)中的常量表達(dá)式表示數(shù)組元素的個(gè)數(shù),也稱為數(shù)組的長(zhǎng)度。它同時(shí)規(guī)定了數(shù)組中各個(gè)數(shù)組元素下標(biāo)的取值范圍。如a[5]表示數(shù)組a有5個(gè)元素,其下標(biāo)從0開始計(jì)算,因此這5個(gè)元素分別為a[0]、a[1]、a[2]、a[3]、a[4]。
例如:
inta[10];
/*說(shuō)明整型數(shù)組a有10個(gè)元素*/
floatb[10],c[20];/*說(shuō)明實(shí)型數(shù)組b有10個(gè)元素,實(shí)型數(shù)組c有20個(gè)元素*/
charch[20];
/*說(shuō)明字符數(shù)組ch有20個(gè)元素*/我們知道,執(zhí)行到變量定義語(yǔ)句時(shí)系統(tǒng)會(huì)在內(nèi)存為變量分配相應(yīng)的存儲(chǔ)空間。例如,為整型變量分配2個(gè)字節(jié),為字符型變量分配1個(gè)字節(jié)。那么,系統(tǒng)是怎樣為數(shù)組變量分配存儲(chǔ)空間的呢?
實(shí)際上,系統(tǒng)會(huì)分配一段連續(xù)的存儲(chǔ)空間來(lái)依次存儲(chǔ)數(shù)組中的各個(gè)數(shù)組元素,如圖7-1所示。為了能夠訪問(wèn)數(shù)組中的各個(gè)元素,系統(tǒng)將這段空間的第一個(gè)內(nèi)存單元地址記入數(shù)組名,即數(shù)組名對(duì)應(yīng)的是數(shù)組的首地址。假設(shè)首地址為10000H,則數(shù)組名對(duì)應(yīng)的地址值即為10000H。因此,數(shù)組名與變量名有著本質(zhì)的區(qū)別:程序中直接使用變量名代表的是該變量中存放的數(shù)據(jù)值;若直接使用數(shù)組名則代表的是該數(shù)組的首地址,它是一個(gè)地址值,而不是數(shù)據(jù)值。變量可被賦值,而數(shù)組名是常量,不能被賦值。圖7-1一維數(shù)組的存儲(chǔ)由于數(shù)組元素是順序存放的,所以很容易可以由數(shù)組的首地址計(jì)算出數(shù)組中第i個(gè)元素的存放地址。因此,數(shù)組是一種可直接存取的線性結(jié)構(gòu)。
系統(tǒng)為數(shù)組分配的存儲(chǔ)空間大小由數(shù)組類型和數(shù)組長(zhǎng)度共同決定,即數(shù)組所占用的存儲(chǔ)空間等于所有數(shù)組元素占用空間之和。例如,對(duì)于數(shù)組定義語(yǔ)句“inta[10];”,由于每個(gè)數(shù)組元素都是int類型,均需要占用2個(gè)字節(jié),所以系統(tǒng)會(huì)分配20個(gè)字節(jié)用來(lái)存儲(chǔ)該數(shù)組。定義數(shù)組還應(yīng)特別注意:
(1)不能在方括號(hào)中用變量來(lái)表示元素的個(gè)數(shù),但是可以用符號(hào)常量或常量表達(dá)式來(lái)表示元素的個(gè)數(shù)??紤]到在程序的后續(xù)維護(hù)過(guò)程中可能需要修改數(shù)組的長(zhǎng)度,因此較好的做法是用宏來(lái)定義數(shù)組的長(zhǎng)度。
例如:
#defineFD5
main()
{
inta[3+2],b[7+FD];
…
}
是合法的。但是下述說(shuō)明方式是錯(cuò)誤的:
main()
{
intn=5;
inta[n];
…
}
(2)允許在同一個(gè)類型說(shuō)明中說(shuō)明多個(gè)數(shù)組和多個(gè)變量。例如:
inta,b,c,d,k1[10],k2[20];
(3)在數(shù)組定義前加const可將數(shù)組變?yōu)椤俺A俊?。例如?/p>
constintmonth[]={31,28,31,30,31,30,31,31,30,31,30,31};
C語(yǔ)言規(guī)定不允許修改常量數(shù)組中各元素的值。將程序執(zhí)行過(guò)程中其值不希望改變的數(shù)組聲明為常量數(shù)組有利于編譯器發(fā)現(xiàn)錯(cuò)誤,避免不必要的錯(cuò)誤發(fā)生。7.1.2一維數(shù)組的引用
雖然所有的數(shù)組元素是用一條語(yǔ)句同時(shí)定義的,但我們可能并不期望同時(shí)操作所有的數(shù)組元素,而有可能只對(duì)其中的某個(gè)或某幾個(gè)數(shù)組元素進(jìn)行操作。因此,在使用數(shù)組時(shí),我們期望能夠?qū)?shù)組元素進(jìn)行單獨(dú)操作,也就是單獨(dú)引用數(shù)組元素。
數(shù)組元素是組成數(shù)組的基本單元,其標(biāo)識(shí)方法為數(shù)組名后跟一個(gè)下標(biāo),下標(biāo)表示該數(shù)組元素在數(shù)組中的順序號(hào)。這樣系統(tǒng)就可以根據(jù)數(shù)組名、數(shù)組類型及數(shù)組元素的下標(biāo)值計(jì)算出該數(shù)組元素的存放地址,進(jìn)而對(duì)該數(shù)組元素進(jìn)行讀/寫操作。一維數(shù)組元素也稱為單下標(biāo)變量,其表示形式為
數(shù)組名[下標(biāo)表達(dá)式]
其中:下標(biāo)表達(dá)式只能為整型常量、整型變量或整型表達(dá)式。若為小數(shù),在編譯時(shí)將自動(dòng)取整。
這里的下標(biāo)表達(dá)式和數(shù)組定義中的常量表達(dá)式在形式上有些相似,但這兩者具有完全不同的含義。數(shù)組定義時(shí)方括號(hào)中給出的是數(shù)組的長(zhǎng)度,即下標(biāo)的有效范圍值;而數(shù)組元素中的下標(biāo)是該元素在數(shù)組中的位置標(biāo)識(shí)。前者只能是常量,后者可以是常量、變量或表達(dá)式。例如,a[5]、a[i]、a[i+j]?都是合法的數(shù)組元素。數(shù)組元素通常也稱為下標(biāo)變量。
注意
對(duì)于“inta[10];”,數(shù)組元素a[10]?是不合法的引用,因?yàn)?0超出了該數(shù)組的有效下標(biāo)范圍。
必須先定義數(shù)組,才能使用下標(biāo)變量。一個(gè)下標(biāo)變量本質(zhì)上相當(dāng)于一個(gè)同類型(數(shù)組類型)的普通變量。例如,若有定義inta[5],則a[0]、a[1]、a[2]、a[3]、a[4]?這5個(gè)下標(biāo)變量在程序中的作用相當(dāng)于5個(gè)普通的整型變量。在C語(yǔ)言中只能逐個(gè)地使用下標(biāo)變量,而不能一次引用整個(gè)數(shù)組。例如,輸出有10個(gè)元素的數(shù)組必須使用循環(huán)語(yǔ)句逐個(gè)輸出各下標(biāo)變量:
for(i=0;i<10;i++)
printf(“%d”,a[i]);
而不能用一個(gè)語(yǔ)句輸出整個(gè)數(shù)組。
對(duì)數(shù)組a,下面的寫法是錯(cuò)誤的:
printf("%d",a);
數(shù)組下標(biāo)可以是任何整型表達(dá)式,如下面的例7.1中的兩個(gè)程序是完全等價(jià)的。但若將程序2中的語(yǔ)句“a[i++]=i;”修改為“a[++i]=i;”,兩個(gè)程序就不再等價(jià)了。因此,當(dāng)下標(biāo)中包含自增操作時(shí)一定要特別注意。
【例7.2】錄入一串?dāng)?shù),然后反向輸出這串?dāng)?shù)。
程序如下:
#include<stdio.h>
#defineN10
/*定義常量N*/
main()
{
inta[N],i;
/*定義長(zhǎng)度為N的數(shù)組a*/
printf(“Enter%dnumbers:”,N);
for(i=0;i<N;i++)
scanf(“%d”,&a[i]); /*從鍵盤輸入10個(gè)數(shù),初始化數(shù)組a*/
printf(“Inreverseorder:”);
for(i=N-1;i>=0;i--)
printf(“%d”,a[i]); /*逆序輸出數(shù)組a中的各個(gè)元素*/
printf("\n");
}從例7.2中不難看到,僅僅通過(guò)變換數(shù)組下標(biāo)就可以方便地訪問(wèn)數(shù)組中的各個(gè)元素。下標(biāo)的變換往往通過(guò)循環(huán)變量的變化來(lái)控制,所以找到它們之間的關(guān)系就成為程序設(shè)計(jì)中處理數(shù)組的關(guān)鍵。另外,這個(gè)程序很好地體現(xiàn)了用宏定義數(shù)組長(zhǎng)度的好處,不但提高了程序的可讀性,而且日后想要修改數(shù)組的長(zhǎng)度時(shí),只需要改一個(gè)地方就能做到“一改全改”,方便又快捷。
數(shù)組元素的下標(biāo)總是從0開始的,所以長(zhǎng)度為n的數(shù)組,其有效的數(shù)組下標(biāo)范圍為0~n-1,因此,只有當(dāng)下標(biāo)表達(dá)式的值在該范圍內(nèi)時(shí)數(shù)組引用才是有效的。但實(shí)際上C語(yǔ)言并不要求對(duì)下標(biāo)范圍進(jìn)行檢查,即編譯器不認(rèn)為數(shù)組下標(biāo)越界是語(yǔ)法錯(cuò)誤。這就造成存在數(shù)組下標(biāo)越界問(wèn)題的程序在編譯時(shí)能通過(guò),執(zhí)行時(shí)卻得不到預(yù)期的正確結(jié)果,甚至運(yùn)行時(shí)會(huì)產(chǎn)生錯(cuò)誤。對(duì)數(shù)組的越界訪問(wèn)會(huì)造成不可預(yù)計(jì)的后果。越界取得的數(shù)據(jù)顯然沒有意義,使用這種數(shù)據(jù)可能導(dǎo)致程序給出莫名其妙的結(jié)果。越界賦值則更危險(xiǎn),這種操作的后果是非??膳碌摹T浇缳x值會(huì)破壞被賦值位置的原有數(shù)據(jù),其后果難以預(yù)料,因?yàn)楦緹o(wú)法知道被這個(gè)操作破壞的到底是什么,可能是其他程序的變量值,也可能是重要的內(nèi)部控制信息。實(shí)際中惡意攻擊者或惡意程序最常用的一種技術(shù)就是設(shè)法造成程序執(zhí)行中出現(xiàn)數(shù)組越界訪問(wèn),并借機(jī)取得被攻擊計(jì)算機(jī)系統(tǒng)的控制權(quán)??傊?,保證對(duì)數(shù)組元素的訪問(wèn)不超出合法范圍是非常重要的。7.1.3一維數(shù)組的初始化
給數(shù)組賦值的方法除了用賦值語(yǔ)句對(duì)數(shù)組元素逐個(gè)賦值外,還可以采用初始化賦值的方法。數(shù)組初始化賦值是指在數(shù)組定義時(shí)給數(shù)組元素賦予初值。數(shù)組初始化是在編譯階段進(jìn)行的,這樣將減少運(yùn)行時(shí)間,提高效率。
初始化賦值的一般形式為
類型說(shuō)明符數(shù)組名[常量表達(dá)式]={值,值,…,值};
其中:在{?}中的各數(shù)據(jù)值即為各元素的初值,各值之間用逗號(hào)間隔。
例如,“inta[10]={0,1,2,3,4,5,6,7,8,9};”相當(dāng)于“a[0]=0;a[1]=1,…,a[9]=9;”。
C語(yǔ)言對(duì)數(shù)組的初始化賦值還有以下幾點(diǎn)規(guī)定:
(1)可以只給部分元素賦初值。當(dāng)?{?}?中值的個(gè)數(shù)少于元素個(gè)數(shù)時(shí),只給前面部分元素賦值,其余元素自動(dòng)賦0值。
例如:
inta[10]={0,1,2,3,4};
表示只給a[0]~a[4]5個(gè)元素賦值,而后5個(gè)元素自動(dòng)賦0值。因此,若想將數(shù)組a中的各元素均初始化為0,可簡(jiǎn)寫為“inta[10]={0};”。
(2)只能給元素逐個(gè)賦值,不能給數(shù)組整體賦值。
例如,給10個(gè)元素全部賦1值,只能寫為
inta[10]={1,1,1,1,1,1,1,1,1,1};
而不能寫為
inta[10]=1;
(3)如給全部元素賦值,則在數(shù)組說(shuō)明中可以不給出數(shù)組元素的個(gè)數(shù),數(shù)組長(zhǎng)度由{?}中值的個(gè)數(shù)決定。
例如,“inta[10]={1,2,3,4,5};”與“inta[]={1,2,3,4,5};”是不等價(jià)的。前一個(gè)數(shù)組長(zhǎng)度為10,而后一個(gè)數(shù)組長(zhǎng)度為5。7.1.4一維數(shù)組應(yīng)用舉例
可以在程序執(zhí)行過(guò)程中對(duì)數(shù)組作動(dòng)態(tài)賦值。這時(shí)可用循環(huán)語(yǔ)句配合scanf函數(shù)逐個(gè)對(duì)數(shù)組元素賦值。
【例7.3】輸入10個(gè)數(shù),輸出其中的最大數(shù)及其序號(hào)。
程序如下:
main()
{
inti,max,maxi,a[10];
printf(“input10numbers:\n”);
for(i=0;i<10;i++)/*用循環(huán)語(yǔ)句配合scanf函數(shù)逐個(gè)對(duì)數(shù)組元素賦值*/
scanf(“%d”,&a[i]);
max=a[0];maxi=0;
for(i=1;i<10;i++)
if(a[i]>max)
{
max=a[i];
maxi=i;
}
printf("max%d:%d\n",maxi,max);
}本例程序中第一個(gè)for語(yǔ)句逐個(gè)輸入10個(gè)數(shù)到數(shù)組a中,然后把a(bǔ)[0]?送入max中。在第二個(gè)for語(yǔ)句中,從a[1]?到a[9]?逐個(gè)與max中的內(nèi)容比較,若比max的值大,則把該下標(biāo)變量送入max中,同時(shí)記下其下標(biāo)值。因此max總是在已比較過(guò)的下標(biāo)變量中的最大者。比較結(jié)束,輸出max及其序號(hào)的值。
【例7.4】
把一個(gè)整數(shù)按大小順序插入已排好序的數(shù)組中。
為了把一個(gè)數(shù)按大小順序插入已排好序的數(shù)組中,應(yīng)首先確定排序是從大到小還是從小到大進(jìn)行的。設(shè)排序是從大到小排序的,則可把欲插入的數(shù)與數(shù)組中的各數(shù)逐個(gè)比較,當(dāng)找到第一個(gè)比插入數(shù)小的元素i時(shí),該元素之前即為插入位置。然后從數(shù)組最后一個(gè)元素開始到該元素為止,逐個(gè)后移一個(gè)單元。最后把插入數(shù)賦予元素i即可。如果被插入數(shù)比所有的元素值都小,則插入最后位置。程序如下:
main()
{
inti,j,p,q,s,n,a[11]={127,3,6,28,54,68,87,105,162,18};
for(i=0;i<10;i++)
{
p=i;q=a[i];
for(j=i+1;j<10;j++)
if(q<a[j])
{p=j;q=a[j];}
if(p!=i)
{s=a[i];a[i]=a[p];a[p]=s;}
printf("%d",a[i]);
}
printf(“\ninputnumber:\n”);
scanf(“%d”,&n);
for(i=0;i<10;i++)
if(n>a[i])
{
for(s=9;s>=i;s--)a[s+1]=a[s];
break;
}
a[i]=n;
for(i=0;i<=10;i++)
printf(“%d”,a[i]);
printf("\n");
}本程序首先對(duì)數(shù)組a中的10個(gè)數(shù)從大到小排序并輸出排序結(jié)果。然后輸入要插入的整數(shù)n。再用一個(gè)for語(yǔ)句把n和數(shù)組元素逐個(gè)比較,當(dāng)發(fā)現(xiàn)有n?>?a[i]?時(shí),則由一個(gè)內(nèi)循環(huán)把i以下各元素值順次后移一個(gè)單元。后移應(yīng)從后向前進(jìn)行(從a[9]?開始到a[i]?為止)。后移結(jié)束,跳出外循環(huán)。插入點(diǎn)為i,把n賦予a[i]?即可。如所有的元素均大于被插入數(shù),則不進(jìn)行后移工作。此時(shí)i=10,結(jié)果是把n賦予a[10]。最后一個(gè)循環(huán)輸出插入n后的數(shù)組各元素值。
程序運(yùn)行時(shí),輸入47。從結(jié)果中可以看出47已插入到54和28之間。 7.2二維數(shù)組
前面討論的一維數(shù)組可以表示數(shù)學(xué)中的向量、數(shù)據(jù)的有限序列等一維線性結(jié)構(gòu)的數(shù)據(jù),但在實(shí)際應(yīng)用中還存在一些不是線性結(jié)構(gòu)的數(shù)據(jù)關(guān)系。例如,數(shù)值計(jì)算中經(jīng)常用到的矩陣,它有兩個(gè)維,不是線性結(jié)構(gòu),矩陣中的元素必須通過(guò)兩個(gè)下標(biāo)指定,程序中如何描述這樣的數(shù)據(jù)呢?
C語(yǔ)言支持定義二維及更高維的數(shù)組,并且把二維數(shù)組看做數(shù)組類型為一維數(shù)組的數(shù)組,即數(shù)組中的所有數(shù)組元素又都是同類型同長(zhǎng)度的一維數(shù)組。三維數(shù)組可看成是數(shù)組類型為二維數(shù)組的數(shù)組,依此類推,n維數(shù)組即為數(shù)組類型為n-1維數(shù)組的數(shù)組。本節(jié)只介紹二維數(shù)組,多維數(shù)組可由二維數(shù)組類推得到。7.2.1二維數(shù)組的定義
二維數(shù)組定義的一般形式為
類型說(shuō)明符數(shù)組名[常量表達(dá)式1][常量表達(dá)式2]
其中:常量表達(dá)式1表示第一維下標(biāo)的長(zhǎng)度;常量表達(dá)式2表示第二維下標(biāo)的長(zhǎng)度。
例如:
inta[3][4];
說(shuō)明了一個(gè)三行四列的數(shù)組,數(shù)組名為a,其下標(biāo)變量的類型為整型。該數(shù)組的下標(biāo)變量共有3?×?4個(gè),即
a[0][0],a[0][1],a[0][2],a[0][3]
a[1][0],a[1][1],a[1][2],a[1][3]
a[2][0],a[2][1],a[2][2],a[2][3]二維數(shù)組在邏輯上是二維的,即其下標(biāo)在兩個(gè)方向上變化,下標(biāo)變量在數(shù)組中的位置也處于一個(gè)平面之中,而不是像一維數(shù)組只是一個(gè)向量。但是,實(shí)際的硬件存儲(chǔ)器卻是連續(xù)編址的,也就是說(shuō)存儲(chǔ)器單元是按一維線性排列的。
要在一維存儲(chǔ)器中存放二維數(shù)組,可有兩種方式:一種是按行排列,即放完一行之后順次放入第二行;另一種是按列排列,即放完一列之后再順次放入第二列。二維數(shù)組a的兩種存放形式如圖7-2所示。圖7-2二維數(shù)組a的兩種存放形式在C語(yǔ)言中,二維數(shù)組是按行排列的,即先存放a[0]?行,再存放a[1]?行,最后存放a[2]行。每行中的四個(gè)元素也是依次存放的。由于數(shù)組a說(shuō)明為int類型,該類型占兩個(gè)字節(jié)的內(nèi)存空間,所以每個(gè)元素均占2個(gè)字節(jié),總的存儲(chǔ)空間為3?×?4?×?2個(gè)字節(jié)。
思考
如何根據(jù)數(shù)組名、數(shù)組類型、各下標(biāo)值計(jì)算多維數(shù)組元素的存放地址?7.2.2二維數(shù)組的引用
二維數(shù)組的元素也稱為雙下標(biāo)變量,其表示形式為
數(shù)組名[下標(biāo)][下標(biāo)]
其中:下標(biāo)應(yīng)為整型常量或整型表達(dá)式。
例如:
a[3][4]
表示a數(shù)組中有三行四列的元素。
同一維數(shù)組一樣,這里每一維的下標(biāo)都必須小于該維的長(zhǎng)度規(guī)定,否則就會(huì)出現(xiàn)數(shù)組越界,造成不可預(yù)知的后果。
就像前面用單重循環(huán)處理一維數(shù)組一樣,雙重循環(huán)是處理二維數(shù)組的理想選擇。
【例7.5】
一個(gè)學(xué)習(xí)小組有5個(gè)人,每個(gè)人有3門課程的考試成績(jī),如表7-1所示。求各門課程的平均成績(jī)和所有課程的總平均成績(jī)??稍O(shè)一個(gè)二維數(shù)組a[5][3]存放5個(gè)人3門課程的成績(jī)。再設(shè)一個(gè)一維數(shù)組v[3]存放所求得的各門課程的平均成績(jī),設(shè)變量average為所有課程的總平均成績(jī)。
程序如下:
main()
{inti,j,s=0,average,v[3],a[5][3];
printf(“inputscore\n”);
for(i=0;i<3;i++)
{
for(j=0;j<5;j++)
{
scanf("%d",&a[j][i]);
s=s+a[j][i];}
v[i]=s/5;
s=0;
}
average=(v[0]+v[1]+v[2])/3;
printf("math:%d\nclanguage:%d\ndbase:%d\n",v[0],v[1],v[2]);
printf("total:%d\n",average);
}程序中首先用了一個(gè)雙重循環(huán)。在內(nèi)循環(huán)中依次讀入某一門課程的各個(gè)學(xué)生的成績(jī),并把這些成績(jī)累加起來(lái),退出內(nèi)循環(huán)后再把該累加成績(jī)除以5送入v[i]之中,這就是該門課程的平均成績(jī)。外循環(huán)共循環(huán)3次,分別求出3門課各自的平均成績(jī)并存放在v數(shù)組之中。退出外循環(huán)之后,把v[0]、v[1]、v[2]相加除以3即得到所有課程的總平均成績(jī)。最后按題意輸出成績(jī)。7.2.3二維數(shù)組的初始化
二維數(shù)組的初始化是指在數(shù)組定義時(shí)給各下標(biāo)變量賦以初值。二維數(shù)組可按行分段賦值,也可按行連續(xù)賦值。
例如,對(duì)數(shù)組a[5][3],按行分段賦值可寫為
inta[5][3]={{80,75,92},{61,65,71},{59,63,70},{85,87,90},{76,77,85}};
按行連續(xù)賦值可寫為
inta[5][3]={80,75,92,61,65,71,59,63,70,85,87,90,76,77,85};
這兩種賦初值的結(jié)果是完全相同的。對(duì)于二維數(shù)組初始化賦值還有以下說(shuō)明:
(1)可以只對(duì)部分元素賦初值,未賦初值的元素自動(dòng)取0值。
例如:
inta[3][3]={{1},{2},{3}};
是對(duì)每一行的第一列元素賦值,未賦值的元素取0值。賦值后各元素的值為
100
200
300
又如:
inta[3][3]={{0,1},{0,0,2},{3}};
賦值后的元素值為
010
002
300
(2)如果對(duì)全部元素賦初值,則第一維的長(zhǎng)度可以不給出。
例如:
inta[3][3]={1,2,3,4,5,6,7,8,9};
可以寫為
inta[][3]={1,2,3,4,5,6,7,8,9};
【例7.6】請(qǐng)以矩陣的形式輸出矩陣A與矩陣B相加之和。
程序如下:
main()
{
inti,j;
inta[5][3]={{80,75,92},{61,65,71},{59,63,70},{85,87,90},{76,77,85}};
intb[5][3]={{1},{0,1},{0,0,1}};
for(i=0;i<3;i++)
{
for(j=0;j<5;j++)
printf(“%4d”,a[i][j]+b[i][j]);
printf(“\n”);
}
}7.2.4二維數(shù)組的分解
數(shù)組是一種構(gòu)造類型的數(shù)據(jù)結(jié)構(gòu)。二維數(shù)組可以看做是由一維數(shù)組的嵌套構(gòu)成的。設(shè)一維數(shù)組的每個(gè)元素又都是一個(gè)數(shù)組,就組成了二維數(shù)組。當(dāng)然,前提是各元素類型必須相同。根據(jù)這樣的分析,一個(gè)二維數(shù)組也可以分解為多個(gè)一維數(shù)組。C語(yǔ)言允許這種分解。
例如,二維數(shù)組a[3][4]可分解為三個(gè)一維數(shù)組,其數(shù)組名分別為a[0]、a[1]、a[2]。對(duì)這三個(gè)一維數(shù)組不需另作說(shuō)明即可使用。這三個(gè)一維數(shù)組都有4個(gè)元素,如一維數(shù)組a[0]的元素為a[0][0]、a[0][1]、a[0][2]、a[0][3]。必須強(qiáng)調(diào)的是,a[0]、a[1]、a[2]不能當(dāng)做數(shù)組元素(下標(biāo)變量)使用,它們是數(shù)組名,不是一個(gè)單純的數(shù)組元素(下標(biāo)變量)。
7.3數(shù)組與運(yùn)算符
7.3.1數(shù)組與算術(shù)/賦值/邏輯運(yùn)算符
因?yàn)閿?shù)組中實(shí)際存儲(chǔ)數(shù)據(jù)的是各個(gè)數(shù)組元素,而數(shù)組名代表的只是數(shù)組首地址(一個(gè)地址常量),所以,只有用數(shù)組元素作為算術(shù)運(yùn)算和邏輯運(yùn)算的操作數(shù)才是有意義的。用數(shù)組名作為操作數(shù)時(shí),實(shí)際參與運(yùn)算的是地址值而不是數(shù)據(jù)值。例如,將數(shù)組a和數(shù)組b中各元素對(duì)應(yīng)相加的結(jié)果存放在數(shù)組c中,則不能簡(jiǎn)單地
寫為
inta[10],b[10],c[10];
c=a+b;/*數(shù)組名中存放的是數(shù)組首地址,并且是常量,不允許修改*/
而應(yīng)該用循環(huán)語(yǔ)句將各個(gè)元素分別相加才能得到想要的結(jié)果:
for(i=0;i<10;i++)
c[i]=a[i]+b[i]另外,對(duì)于賦值運(yùn)算也是如此。我們可以利用賦值運(yùn)算將變量a的值賦值給變量b,卻不能簡(jiǎn)單地用賦值運(yùn)算符完成數(shù)組之間的賦值操作。例如:
#defineN10
main()
{
inta[N],b[N];
printf(“Enter%dnumbers:”,N);
for(i=0;i<N;i++)
scanf(“%d”,&a[i]);
b=a;
printf(“b:”);
for(i=0;i<N;i++)
printf(“%d”,b[i]);
printf("\n");
}編譯該程序,編譯器會(huì)給出錯(cuò)誤信息,為什么呢?首先,C語(yǔ)言的賦值運(yùn)算符不支持?jǐn)?shù)組賦值。其次,前面我們講到數(shù)組名中存放的是數(shù)組首地址,它是常量,是不允許出現(xiàn)在賦值運(yùn)算符的左側(cè)的。
那么要想完成數(shù)組間的復(fù)制應(yīng)該如何做呢?最簡(jiǎn)單的辦法就是利用循環(huán)對(duì)數(shù)組元素進(jìn)行逐個(gè)復(fù)制。另一種方法是使用string.h中的內(nèi)存復(fù)制函數(shù)memcpy。例如,將數(shù)組a復(fù)制給數(shù)組b,使用memcpy的寫法為
memcpy(b,a,sizeof(b));
一般地,對(duì)于大型數(shù)組,使用memcpy函數(shù)效率會(huì)比較高。7.3.2對(duì)數(shù)組使用sizeof運(yùn)算符
前面講過(guò)對(duì)變量名使用sizeof運(yùn)算符可以得到該變量占用內(nèi)存的字節(jié)數(shù),同樣對(duì)數(shù)組名使用sizeof運(yùn)算符也可以確定數(shù)組的大小,即獲得數(shù)組占用內(nèi)存的字節(jié)數(shù)。
例如,有
inta[10];
則sizeof(a)就等于20。
同理,也可以用sizeof運(yùn)算符計(jì)算某數(shù)組元素的大小。例如:
sizeof(a[0])因此,數(shù)組的長(zhǎng)度就可以表示為
sizeof(a)/sizeof(a[0])
將上式用于程序中,即使日后需要修改數(shù)組的長(zhǎng)度,循環(huán)也不需要修改。例如:
for(i=0;i<sizeof(a)/sizeof(a[0]);i++)
a[i]=0;
通常在程序中定義靜態(tài)“求”數(shù)組元素個(gè)數(shù)的宏(帶參數(shù)的宏):
#defineNUM(ax)sizeof(ax)/sizeof(ax[0])
7.4數(shù)?組?與?函?數(shù)
7.4.1數(shù)組元素作為函數(shù)實(shí)參
數(shù)組元素即下標(biāo)變量本質(zhì)上與普通變量并無(wú)區(qū)別,因此它作為函數(shù)實(shí)參使用與普通變量作為函數(shù)實(shí)參使用是完全相同的。此時(shí),與之對(duì)應(yīng)的形參必定是同類型(數(shù)組類型)的普通變量。在發(fā)生函數(shù)調(diào)用時(shí),系統(tǒng)為形參分配存儲(chǔ)空間,使得作為實(shí)參的數(shù)組元素與形參變量占用不同的存儲(chǔ)空間,然后將實(shí)參數(shù)組元素的值傳送給形參變量,實(shí)現(xiàn)“單向值傳遞”,函數(shù)執(zhí)行過(guò)程中對(duì)形參值的修改不會(huì)影響實(shí)參數(shù)組元素的值。
【例7.7】判別一個(gè)整數(shù)數(shù)組中各元素的值,若大于0則輸出該值,若小于等于0則輸出0值。
程序如下:
voidnzp(intv)
{
if(v>0)
printf(“%d”,v);
else
printf(“%d”,0);
}
main()
{
inta[5],i;
printf(“input5numbers\n”);
for(i=0;i<5;i++)
{
scanf(“%d”,&a[i]);
nzp(a[i]);
}
}本程序中首先定義一個(gè)無(wú)返回值函數(shù)nzp,并說(shuō)明其形參v為整型變量。在函數(shù)體中根據(jù)v值輸出相應(yīng)的結(jié)果。在main函數(shù)中用一個(gè)for語(yǔ)句輸入數(shù)組各元素,每輸入一個(gè)就以該元素作為實(shí)參調(diào)用一次nzp函數(shù),即把a(bǔ)[i]的值傳送給形參v,供nzp函數(shù)使用。7.4.2數(shù)組名作為函數(shù)參數(shù)
我們知道數(shù)組名對(duì)應(yīng)的是一個(gè)地址值—數(shù)組首地址,那么,數(shù)組名作為函數(shù)參數(shù)時(shí)該用什么樣的形參與之對(duì)應(yīng)呢?函數(shù)調(diào)用時(shí)的參數(shù)傳遞又是如何規(guī)定的呢?
其實(shí),無(wú)論是數(shù)組名作為函數(shù)實(shí)參還是數(shù)組元素作為函數(shù)實(shí)參,其函數(shù)間的數(shù)據(jù)傳遞都遵循“單向值傳遞”的原則。但由于數(shù)組名中存放的是一個(gè)地址值(數(shù)組首地址),而數(shù)組元素中存放的是普通數(shù)據(jù)值,又使得兩者之間存在著本質(zhì)的區(qū)別。第一,數(shù)組元素作為實(shí)參時(shí),只要數(shù)組類型和函數(shù)形參變量的類型一致,那么作為下標(biāo)變量的數(shù)組元素的類型也和函數(shù)形參變量的類型是一致的。因此,并不要求函數(shù)的形參也是下標(biāo)變量。換句話說(shuō),對(duì)數(shù)組元素的處理是按普通變量對(duì)待的。數(shù)組名作為函數(shù)參數(shù)時(shí),則要求形參和相對(duì)應(yīng)的實(shí)參都必須是類型相同的數(shù)組,且有明確的數(shù)組說(shuō)明。當(dāng)形參和實(shí)參二者不一致時(shí),即會(huì)發(fā)生錯(cuò)誤。第二,普通變量或下標(biāo)變量作為函數(shù)參數(shù)時(shí),形參變量和實(shí)參變量占用由編譯系統(tǒng)分配的兩個(gè)不同的內(nèi)存單元。在函數(shù)調(diào)用時(shí)發(fā)生的值傳送是把實(shí)參變量的值賦予形參變量。而數(shù)組名作為函數(shù)參數(shù)時(shí),不是進(jìn)行值的傳送,即不是把實(shí)參數(shù)組的每一個(gè)元素的值都賦予形參數(shù)組的各個(gè)元素,而僅僅是傳送一個(gè)地址值。這是因?yàn)閷?shí)際上形參數(shù)組并不存在,編譯系統(tǒng)不為形參數(shù)組分配實(shí)際的內(nèi)存。那么,數(shù)據(jù)的傳送是如何實(shí)現(xiàn)的呢?在前面我們?cè)榻B過(guò),數(shù)組名中存放的是數(shù)組的首地址。因此,這里的“單向值傳遞”只是將實(shí)參數(shù)組名中的地址值傳送給形參數(shù)組名。這樣當(dāng)形參數(shù)組名取得該首地址之后,就可以訪問(wèn)實(shí)參數(shù)組了。實(shí)際上,形參數(shù)組和實(shí)參數(shù)組為同一數(shù)組,對(duì)應(yīng)內(nèi)存中的同一段空間。圖7-3說(shuō)明了這種情形。圖中設(shè)a為實(shí)參數(shù)組,類型為整型。a占用以2000為首地址(起始地址)的一塊內(nèi)存區(qū)。b為形參數(shù)組名。當(dāng)發(fā)生函數(shù)調(diào)用時(shí),進(jìn)行地址傳送,把實(shí)參數(shù)組a的首地址傳送給形參數(shù)組名b,于是b也取得該地址2000。因此,a、b兩數(shù)組共同占用以2000為首地址的一段連續(xù)內(nèi)存單元。從圖中還可以看出,a和b下標(biāo)相同的元素實(shí)際上也占用相同的兩個(gè)內(nèi)存單元(整型數(shù)組每個(gè)元素占兩個(gè)字節(jié))。例如,a[0]?和b[0]?都占用2000和2001單元,當(dāng)然a[0]?等于b[0]。依此類推,則有a[i]等于b[i]。圖7-3數(shù)組名作為函數(shù)參數(shù)
【例7.8】多項(xiàng)式求值。設(shè)數(shù)組p中保存著多項(xiàng)式anxn+an-1xn-1+…+a1x+a0的各項(xiàng)系數(shù),元素p[i]存放系數(shù)ai。要求寫一個(gè)函數(shù)求出數(shù)組p表示的多項(xiàng)式在某個(gè)指定點(diǎn)x的值。
有多種方法可以實(shí)現(xiàn)多項(xiàng)式求值,下面介紹最快速的秦九韶多項(xiàng)式算法。根據(jù)數(shù)學(xué)知識(shí),任何多項(xiàng)式均可以變換為下面的規(guī)范形式:按照這個(gè)公式,求值的循環(huán)可以寫為
for(sum=0.0,i=n-1;i>=0;i--)
sum=sum*x+p[i];
完整的程序如下:
#include“stdio.h”
#defineN6
main()
{
doublef(doublep[],doublex);
doublex,p[N]={2.3,1.4,5.2,6.7,8.4,1.3};
printf(“pleaseinputx:”);
scanf("%lf",&x);
printf(“\nf(%lf)=%lf\n”,x,f(p,x));
}
doublef(doubleq[],doublex)
{
doublesum;
inti;
for(sum=0.0,i=N-1;i>=0;i--)
sum=sum*x+q[i];
returnsum;
}如果在上述程序中的函數(shù)f中加入修改數(shù)組q中元素的語(yǔ)句,此時(shí)在主函數(shù)中輸出數(shù)組p時(shí),其相應(yīng)的數(shù)組元素也會(huì)發(fā)生改變,這就說(shuō)明了實(shí)參數(shù)組p與形參數(shù)組q是共用存儲(chǔ)空間的。讀者可自行測(cè)試。
第三,前面已經(jīng)討論過(guò),變量作為函數(shù)參數(shù)時(shí),所進(jìn)行的值傳送是單向的,即只能從實(shí)參傳向形參,不能從形參傳回實(shí)參。形參的初值和實(shí)參相同,而形參的值發(fā)生改變后,實(shí)參并不變化,兩者的終值是不同的。而當(dāng)數(shù)組名作為函數(shù)參數(shù)時(shí),情況則不同。由于實(shí)際上形參和實(shí)參為同一數(shù)組,因此當(dāng)形參數(shù)組發(fā)生變化時(shí),實(shí)參數(shù)組也隨之變化。當(dāng)然這種情況不能理解為發(fā)生了“雙向”的值傳遞。但從實(shí)際情況來(lái)看,調(diào)用函數(shù)之后,實(shí)參數(shù)組的值將隨著形參數(shù)組值的變化而變化。
【例7.9】題目同例7.7,改用數(shù)組名作為函數(shù)參數(shù)。
程序如下:
voidnzp(inta[5])
{
inti;
printf(“\nvaluesofarrayaare:\n”);
for(i=0;i<5;i++)
{
if(a[i]<0)a[i]=0;
printf(“%d”,a[i]);
}
}
main()
{
intb[5],i;
printf(“\ninput5numbers:\n”);
for(i=0;i<5;i++)
scanf(“%d”,&b[i]);
printf(“initialvaluesofarraybare:\n”);
for(i=0;i<5;i++)
printf(“%d”,b[i]);
nzp(b);
printf(“\nlastvaluesofarraybare:\n”);
for(i=0;i<5;i++)
printf("%d",b[i]);
}本程序中函數(shù)nzp的形參為整型數(shù)組a,長(zhǎng)度為5。主函數(shù)中實(shí)參數(shù)組b也為整型,長(zhǎng)度也為5。在主函數(shù)中首先輸入數(shù)組b的值,然后輸出數(shù)組b的初始值。之后以數(shù)組名b為實(shí)參調(diào)用nzp函數(shù)。在nzp中,按要求把負(fù)值單元清0,并輸出形參數(shù)組a的值。返回主函數(shù)之后,再次輸出數(shù)組b的值。從運(yùn)行結(jié)果可以看出,數(shù)組b的初值和終值是不同的,數(shù)組b的終值和數(shù)組a是相同的。這說(shuō)明實(shí)參和形參為同一數(shù)組,它們的值同時(shí)得以改變。用數(shù)組名作為函數(shù)參數(shù)時(shí)還應(yīng)注意以下幾點(diǎn):
(1)形參數(shù)組和實(shí)參數(shù)組的類型必須一致,否則將引起錯(cuò)誤。
(2)形參數(shù)組和實(shí)參數(shù)組的長(zhǎng)度可以不相同,因?yàn)樵谡{(diào)用時(shí),只傳送首地址而不檢查形參數(shù)組的長(zhǎng)度。當(dāng)形參數(shù)組的長(zhǎng)度與實(shí)參數(shù)組不一致時(shí),雖不會(huì)出現(xiàn)語(yǔ)法錯(cuò)誤(編譯能通過(guò)),但程序執(zhí)行結(jié)果可能與實(shí)際不符(如例7.10所示),這是應(yīng)予以注意的。
(3)在函數(shù)形參表中,允許不給出形參數(shù)組的長(zhǎng)度,或用一個(gè)變量來(lái)表示數(shù)組元素的個(gè)數(shù)。例如,可以寫為
voidnzp(inta[])
或?qū)憺?/p>
voidnzp(inta[],intn)
其中形參數(shù)組a沒有給出長(zhǎng)度,而由n值動(dòng)態(tài)地表示數(shù)組的長(zhǎng)度。n的值由主調(diào)函數(shù)的實(shí)參進(jìn)行傳送,如例7.11。
(4)多維數(shù)組也可以作為函數(shù)的參數(shù)。在函數(shù)定義時(shí)對(duì)形參數(shù)組可以指定每一維的長(zhǎng)度,也可省去第一維的長(zhǎng)度。因此,以下寫法都是合法的:
intMA(inta[3][10])
或
intMA(inta[][10])
【例7.10】把例7.9修改如下:
voidnzp(inta[8])
{
inti;
printf(“\nvaluesofarrayaare:\n”);
for(i=0;i<8;i++)
{
if(a[i]<0)a[i]=0;
printf(“%d”,a[i]);
}
}
main()
{
intb[5],i;
printf(“\ninput5numbers:\n”);
for(i=0;i<5;i++)
scanf(“%d”,&b[i]);
printf(“initialvaluesofarraybare:\n”);
for(i=0;i<5;i++)
printf(“%d”,b[i]);
nzp(b);
printf(“\nlastvaluesofarraybare:\n”);
for(i=0;i<5;i++)
printf("%d",b[i]);
}本程序與例7.9的程序相比,nzp函數(shù)的形參數(shù)組長(zhǎng)度改為8,函數(shù)體中,for語(yǔ)句的循環(huán)條件也改為i?<?8。因此,形參數(shù)組a和實(shí)參數(shù)組b的長(zhǎng)度不一致。編譯能夠通過(guò),但從結(jié)果來(lái)看,數(shù)組a的元素a[5]、a[6]、a[7]?顯然是無(wú)意義的。
【例7.11】把例7.9修改如下:
voidnzp(inta[],intn)
{
inti;
printf(“\nvaluesofarrayaare:\n”);
for(i=0;i<n;i++)
{
if(a[i]<0)a[i]=0;
printf(“%d”,a[i]);
}
}
main()
{
intb[5],i;
printf(“\ninput5numbers:\n”);
for(i=0;i<5;i++)
scanf(“%d”,&b[i]);
printf(“initialvaluesofarraybare:\n”);
for(i=0;i<5;i++)
printf(“%d”,b[i]);
nzp(b,5);
printf(“\nlastvaluesofarraybare:\n”);
for(i=0;i<5;i++)
printf("%d",b[i]);
} 7.5字符數(shù)組與字符串
字符數(shù)組就是數(shù)組類型為字符類型的數(shù)組,用于保存一系列字符。由于人們經(jīng)常用C語(yǔ)言編寫處理字符序列或各種文本的程序,因此C語(yǔ)言為處理字符數(shù)組提供了專門的支持。
字符串是典型的非數(shù)值對(duì)象,其存儲(chǔ)模式是以字符數(shù)組作為存儲(chǔ)空間,結(jié)尾加結(jié)束標(biāo)志符?'\0'。對(duì)字符串的基本操作主要通過(guò)標(biāo)準(zhǔn)庫(kù)提供的函數(shù)來(lái)實(shí)現(xiàn)。7.5.1字符數(shù)組的基本語(yǔ)法知識(shí)
1.字符數(shù)組的定義
字符數(shù)組的定義形式與前面介紹的數(shù)值數(shù)組相同。
例如:
charc[10];
由于字符型和整型通用,也可以定義為intc[10],但這時(shí)每個(gè)數(shù)組元素占2個(gè)字節(jié)的內(nèi)存單元。
字符數(shù)組也可以是二維或多維數(shù)組。
例如:
charc[5][10];
即為二維字符數(shù)組。
2.字符數(shù)組的初始化
字符數(shù)組也允許在定義時(shí)作初始化賦值。
例如:
charc[10]={‘C’,‘’,‘p’,‘r’,‘o’,‘g’,‘r’,‘a(chǎn)’,‘m’};
賦值后各元素的值為
數(shù)組c c[0]的值為‘C’
c[1]的值為‘’
c[2]的值為‘p’
c[3]的值為‘r’
c[4]的值為‘o’
c[5]的值為‘g’
c[6]的值為‘r’
c[7]的值為‘a(chǎn)’
c[8]的值為'm'其中c[9]?未賦值,系統(tǒng)自動(dòng)賦予0值。
當(dāng)對(duì)全體元素賦初值時(shí)也可以省去長(zhǎng)度說(shuō)明。
例如:
charc[]={'C','','p','r','o','g','r','a','m'};
這時(shí)數(shù)組c的長(zhǎng)度自動(dòng)定為9。
3.字符數(shù)組的引用
字符數(shù)組的引用與數(shù)值數(shù)組的引用完全一致。
【例7.12】
二維字符數(shù)組的輸出。
程序如下:
main()
{
inti,j;
chara[][5]={{‘B’,‘A’,‘S’,‘I’,‘C’,},{‘d’,‘B’,‘A’,‘S’,‘E’}};
for(i=0;i<=1;i++)
{
for(j=0;j<=4;j++)
printf(“%c”,a[i][j]);
printf(“\n”);
}
}7.5.2字符串和字符串結(jié)束標(biāo)志
在C語(yǔ)言中沒有專門的字符串變量,通常用一個(gè)字符數(shù)組來(lái)存放一個(gè)字符串。前面介紹字符串常量時(shí),已說(shuō)明字符串總是以?'\0'?作為串的結(jié)束符。因此當(dāng)把一個(gè)字符串存入一個(gè)數(shù)組時(shí),也把結(jié)束符?'\0'?存入數(shù)組,并以此作為該字符串是否結(jié)束的標(biāo)志。有了?'\0'?標(biāo)志后,就不必再用字符數(shù)組的長(zhǎng)度來(lái)判斷字符串的長(zhǎng)度了。
C語(yǔ)言允許用字符串的方式對(duì)數(shù)組作初始化賦值。
例如:
charc[]={‘C’,‘’,‘p’,‘r’,‘o’,‘g’,‘r’,‘a(chǎn)’,‘m’};
可寫為
charc[]={“Cprogram”};
或去掉?{}?寫為
charc[]="Cprogram";
用字符串方式賦值比用字符逐個(gè)賦值要多占一個(gè)字節(jié),用于存放字符串結(jié)束標(biāo)志?'\0'。上面的數(shù)組c在內(nèi)存中的實(shí)際存放情況為‘\0’?是由C編譯系統(tǒng)自動(dòng)加上的。由于采用了?‘\0’?標(biāo)志,所以在用字符串賦初值時(shí)一般無(wú)須指定數(shù)組的長(zhǎng)度,而由系統(tǒng)自行處理。
思考
能否直接將一個(gè)字符串賦值給一個(gè)字符數(shù)組?為什么?
例如:
charc[10];
c="Cprogram";
根據(jù)前面的知識(shí),我們知道字符串常量也是以字符數(shù)組的方式存儲(chǔ)的,編譯器把它看做是一個(gè)地址值(存放字符串的內(nèi)存單元的首地址)。雖然數(shù)組名中存放的也是地址值,但因?yàn)樗浅A?,所以不能通過(guò)賦值的方式改變它的值。因此,上述語(yǔ)句是非法的。7.5.3字符數(shù)組的輸入/輸出
在采用字符串方式初始化賦值后,字符數(shù)組的輸入/輸出將變得簡(jiǎn)單方便。
除了上述用字符串賦初值的辦法外,還可用scanf函數(shù)和printf函數(shù)一次性輸入/輸出一個(gè)字符數(shù)組中的字符串,而不必使用循環(huán)語(yǔ)句逐個(gè)地輸入/輸出每個(gè)字符。
【例7.13】以?“%s”?格式輸出字符串。
程序如下:
main()
{
charc[]=“BASIC\ndBASE”;
printf("%s\n",c);
}
注意
在本例的printf函數(shù)中,使用的格式控制符為?“%s”,表示輸出的是一個(gè)字符串,而在輸出表列中給出數(shù)組名即可。不能寫為
printf(“%s”,c[]);
【例7.14】以?“%s”?格式輸入、輸出字符數(shù)組。
程序如下:
main()
{
charst[15];
printf(“inputstring:\n”);
scanf(“%s”,st);
printf("%s\n",st);
}本例中由于定義數(shù)組長(zhǎng)度為15,因此輸入的字符串長(zhǎng)度必須小于15,以留出一個(gè)字節(jié)用于存放字符串結(jié)束標(biāo)志?'\0'。應(yīng)該說(shuō)明的是,對(duì)一個(gè)字符數(shù)組,如果不作初始化賦值,則必須說(shuō)明數(shù)組長(zhǎng)度。還應(yīng)該特別注意的是,當(dāng)用scanf函數(shù)輸入字符串時(shí),字符串中不能含有空格,否則將以空格作為串的結(jié)束符。
例如,當(dāng)輸入的字符串中含有空格時(shí),運(yùn)行情況為
inputstring:
thisisabook
輸出為
this
【例7.15】以?“%s”?格式輸入、輸出字符串時(shí)對(duì)“空格”應(yīng)作特殊處理。
程序如下:
main()
{
charst1[6],st2[6],st3[6],st4[6];
printf(“inputstring:\n”);
scanf(“%s%s%s%s”,st1,st2,st3,st4);
printf("%s%s%s%s\n",st1,st2,st3,st4);
}本程序分別設(shè)了四個(gè)數(shù)組,輸入的一行字符以空格分段分別裝入四個(gè)數(shù)組。然后分別輸出這四個(gè)數(shù)組中的字符串。
在前面介紹過(guò),scanf的各輸入項(xiàng)必須以地址方式出現(xiàn),如&a、&b等,但在例7.15中卻是以數(shù)組名方式出現(xiàn)的,這是為什么呢?這是由于,在C語(yǔ)言中規(guī)定,數(shù)組名就代表了該數(shù)組的首地址,整個(gè)數(shù)組是以首地址開頭的一塊連續(xù)的內(nèi)存單元。例如,有字符數(shù)組charc[10],在內(nèi)存中可表示如下:設(shè)數(shù)組c的首地址為2000,也就是說(shuō)c[0]?單元地址為2000,則數(shù)組名c就代表這個(gè)首地址,因此在c前面不能再加地址運(yùn)算符&。如果寫做“scanf("%s",&c);”則是錯(cuò)誤的。在執(zhí)行函數(shù)printf("%s",c)時(shí),按數(shù)組名c找到首地址,然后逐個(gè)輸出數(shù)組中各個(gè)字符直到遇到字符串終止標(biāo)志?'\0'?為止。7.5.4字符串處理函數(shù)
C語(yǔ)言提供了豐富的字符串處理函數(shù),大致可分為字符串的輸入、輸出、合并、修改、比較、轉(zhuǎn)換、復(fù)制、搜索幾類。使用這些函數(shù)可大大減輕編程的負(fù)擔(dān)。要使用字符串函數(shù)的輸入/輸出,在程序中應(yīng)包含頭文件?"stdio.h",使用其他字符串函數(shù)則應(yīng)包含頭文件?"string.h"。
下面介紹幾個(gè)最常用的字符串函數(shù)。
1.字符串輸出函數(shù)puts
格式:
puts(字符數(shù)組名)
功能:把字符數(shù)組中的字符串輸出到顯示器,即在屏幕上顯示該字符串。
【例7.16】puts函數(shù)的使用。
程序如下:
#include“stdio.h”
main()
{
charc[]=“BASIC\ndBASE”;
puts(c);
}
從程序中可以看出,puts函數(shù)中可以使用轉(zhuǎn)義字符,因此輸出結(jié)果成為兩行。puts函數(shù)完全可以由printf函數(shù)取代。當(dāng)需要按一定格式輸出時(shí),通常使用printf函數(shù)。
2.字符串輸入函數(shù)gets
格式:
gets(字符數(shù)組名)
功能:從標(biāo)準(zhǔn)輸入設(shè)備鍵盤上輸入一個(gè)字符串。
本函數(shù)得到一個(gè)函數(shù)值,即為該字符數(shù)組的首地址。
【例7.17】gets函數(shù)的使用。
程序如下:
#include“stdio.h”
main()
{
charst[15];
printf(“inputstring:\n”);
gets(st);
puts(st);
}
3.字符串連接函數(shù)strcat
格式:
strcat(字符數(shù)組名1,字符數(shù)組名2)
功能:把字符數(shù)組2中的字符串連接到字符數(shù)組1中字符串的后面,并刪去字符串1后的串標(biāo)志?'\0'。本函數(shù)返回值是字符數(shù)組1的首地址。
【例7.18】strcat函數(shù)的使用。
程序如下:
#include“string.h”
main()
{
staticcharst1[30]=“Mynameis”;
intst2[10];
printf(“inputyourname:\n”);
gets(st2);
strcat(st1,st2);
puts(st1);
}
4.字符串拷貝函數(shù)strcpy
格式:
strcpy(字符數(shù)組名1,字符數(shù)組名2)
功能:把字符數(shù)組2中的字符串拷貝到字符數(shù)組1中,串結(jié)束標(biāo)志?'\0'?也一同拷貝。字符數(shù)名2也可以是一個(gè)字符串常量。這時(shí)相當(dāng)于把一個(gè)字符串賦予一個(gè)字符數(shù)組。
【例7.19】strcpy函數(shù)的使用。
程序如下:
#include“string.h”
main()
{
charst1[15],st2[]=“CLanguage”;
strcpy(st1,st2);
puts(st1);printf("\n");
}
本函數(shù)要求字符數(shù)組1有足夠的長(zhǎng)度,否則不能全部裝入所拷貝的字符串。
5.字符串比較函數(shù)strcmp
格式:
strcmp(字符數(shù)組名1,字符數(shù)組名2)
功能:按照ASCII碼順序比較兩個(gè)數(shù)組中的字符串,并由函數(shù)返回值返回比較結(jié)果。
字符串1=字符串2,返回值=0;
字符串2>字符串2,返回值>0;
字符串1<字符串2,返回值<0。
本函數(shù)也可用于比較兩個(gè)字符串常量,或比較數(shù)組和字符串常量。
【例7.20】strcmp函數(shù)的使用。
程序如下:
#include“string.h”
main()
{
intk;
staticcharst1[15],st2[]=“CLanguage”;
printf(“inputastring:\n”);
gets(st1);
k=strcmp(st1,st2);
if(k==0)printf(“st1=st2\n”);
if(k>0)printf(“st1>st2\n”);
if(k<0)printf("st1<st2\n");
}本程序中把輸入的字符串和數(shù)組st2中的串進(jìn)行比較,比較結(jié)果返回到k中,根據(jù)k值再輸出結(jié)果提示串。當(dāng)輸入為dBASE時(shí),由ASCII碼可知?"dBASE"?大于?"CLanguage",故k?>?0,輸出結(jié)果為?"st1>st2"。
6.測(cè)字符串長(zhǎng)度函數(shù)strlen
格式:
strlen(字符數(shù)組名)
功能:測(cè)字符串的實(shí)際長(zhǎng)度(不含字符串結(jié)束標(biāo)志?'\0')并將其作為函數(shù)返回值。
【例7.21】strlen函數(shù)的使用。
程序如下:
#include“string.h”
main()
{
intk;
staticcharst[]=“CLanguage”;
k=strlen(st);
printf("Thelengthofthestringis%d\n",k);
}
7.6數(shù)組應(yīng)用實(shí)例
7.6.1數(shù)組中的查找算法
查找一般有幾種情況,如查找特定元素、查找最大元素、查找最小元素等。而且一般情況下的查找都需要兩種結(jié)果,即是否存在該元素及該元素在什么位置。
數(shù)組的查找是指根據(jù)給定的某個(gè)值,在數(shù)組中查找一個(gè)等于給定值的數(shù)組元素。若數(shù)組中存在一個(gè)這樣的數(shù)組元素,則稱查找是成功的;若數(shù)組中不存在這樣一個(gè)數(shù)組元素,則稱查找不成功。
1.順序查找
順序查找算法是最普通的查找算法,其實(shí)現(xiàn)最為簡(jiǎn)單,也相當(dāng)實(shí)用。在我們不知道待查找的數(shù)組是否有序的情況下,此算法很容易使用。
順序查找的基本思想非常簡(jiǎn)單,就是依次將數(shù)組的第一個(gè)元素到數(shù)組的最后一個(gè)元素與給定值進(jìn)行比較,最終得出查找成功或查找不成功的結(jié)論。
查找一個(gè)數(shù)組中的特定元素,返回該元素的位置,設(shè)定返回?-1時(shí)表示不存在。用函數(shù)實(shí)現(xiàn)的順序查找算法如下:
intsearch(inta[],intkey,intn)
{
inti;
for(i=0;i<n;i++) /*查找范圍0~n-1*/
if(a[i]==key) /*查找元素key?*/
returni;
/*查找成功*/
return-1;
/*查找失敗*/
}
2.折半查找
折半查找的算法思想是將數(shù)列按有序化(遞增或遞減)排列,查找過(guò)程中采用跳躍式方式查找,即先以有序數(shù)列的中點(diǎn)位置為比較對(duì)象,如果要找的元素值小于該中點(diǎn)元素,則將待查序列縮小為左半部分,否則為右半部分。通過(guò)一次比較,將查找區(qū)間縮小一半。折半查找是一種高效的查找方法,它可以明顯減少比較次數(shù),提高查找效率。但是,折半查找的先決條件是查找表中的數(shù)據(jù)元素必須有序。算法描述如下:
(1)確定整個(gè)查找區(qū)間的中間位置:mid=(left?+?right)/2。
(2)用待查關(guān)鍵字值與中間位置的關(guān)鍵字值進(jìn)行比較。若相等,則查找成功;若前者大于后者,則在后(右)半個(gè)區(qū)域繼續(xù)進(jìn)行折半查找;若前者小于后者,則在前(左)半個(gè)區(qū)域繼續(xù)進(jìn)行折半查找。
(3)對(duì)確定的縮小區(qū)域再按折半公式重復(fù)上述步驟。最后,得到結(jié)果:查找成功或查找失敗。
查找一個(gè)數(shù)組中的特定元素,返回該元素的位置,設(shè)定返回?-1時(shí)表示不存在。用函數(shù)實(shí)現(xiàn)的折半查找算法如下:
intsearch_Bin(inta[],intkey,intn)
{
intlow,high,mid;
low=0;high=n-1; /*置區(qū)間初值*/
while(low<=high){
mid=(low+high)/2;
if(key==a[mid])returnmid; /*待查元素位置*/
elseif(key<a[mid])high=mid-1;
elselow=mid+1; /*繼續(xù)在后半?yún)^(qū)間進(jìn)行查找*/
}
return-1;/*不存在待查元素*/
}7.6.2數(shù)組中的排序算法
數(shù)組排序是指將數(shù)組中的各個(gè)元素按照某種規(guī)則(從大到小、從小到大等)重新排列。常見的排序算法包括交換排序、選擇排序、插入排序和歸并排序,下面僅對(duì)前兩種算法作一介紹。
1.交換排序
交換排序包含冒泡排序(bubblesort)和快速排序(quicksort)。
1)冒泡排序
冒泡排序的基本思想是:依次比較相鄰的兩個(gè)數(shù),將小數(shù)放在前面,大數(shù)放在后面。即在第一趟:首先比較第1個(gè)數(shù)和第2個(gè)數(shù),將小數(shù)放前,大數(shù)放后;然后比較第2個(gè)數(shù)和第3個(gè)數(shù),將小數(shù)放前,大數(shù)放后;如此繼續(xù),直至比較最后兩個(gè)數(shù),將小數(shù)放前,大數(shù)放后。至此第一趟結(jié)束,將最大的數(shù)放到了最后。在第二趟:仍從第一對(duì)數(shù)開始比較(因?yàn)榭赡苡捎诘?個(gè)數(shù)和第3個(gè)數(shù)的交換,使得第1個(gè)數(shù)不再小于第2個(gè)數(shù)),將小數(shù)放前,大數(shù)放后,一直比較到倒數(shù)第二個(gè)數(shù)(倒數(shù)第一的位置上已經(jīng)是最大的),第二趟結(jié)束,在倒數(shù)第二的位置上得到一個(gè)新的最大數(shù)(其實(shí)在整個(gè)數(shù)列中是第二大的數(shù))。如此下去,重復(fù)以上過(guò)程,直至最終完成排序。由于在排序過(guò)程中總是小數(shù)往前放,大數(shù)往后放,相當(dāng)于氣泡往上升,所以稱做冒泡排序。完整程序如下:
voidbubble_Sort(inta[],intn)
{
intw;
i=n-1;
while(i>1){
lastExchangeIndex=1;
for(j=0;j<i;j++)
if(a[j+1]<a[j])
{/*逆序*/
w=a[j];a[j]=a[j+1];a[j+1]=w; /*交換*/
lastExchangeIndex=j;
}
i=lastExchangeIndex;
/*無(wú)序序列的最后記錄位置*/
}
}
2)快速排序
快速排序的基本思想是:選擇數(shù)組元素e作為“分割元素”,然后重新排列數(shù)組,使得位于分割元素e之前的元素都是小于或等于e的,而位于分割元素e之后的元素都是大于或等于e的。然后,再分別對(duì)前半部分的數(shù)組和后半部分的數(shù)組進(jìn)行快速排序。顯然,快速排序的過(guò)程具有結(jié)構(gòu)自相似性,用遞歸函數(shù)實(shí)現(xiàn)最為簡(jiǎn)單。首先定義函數(shù)split實(shí)現(xiàn)第一步中的分割任務(wù)??稍诔绦蛑惺褂脙蓚€(gè)標(biāo)記:low和high。開始,low指向數(shù)組中的第一個(gè)元素,而high指向末尾元素。首先把第一個(gè)元素(分割元素)復(fù)制給一個(gè)臨時(shí)存儲(chǔ)單元,從而在數(shù)組中留出一個(gè)“空位”。接下來(lái),從右向左移動(dòng)high,直到high指向小于分割元素的數(shù)時(shí)停止。然后把這個(gè)數(shù)復(fù)制給low指向的空位,這將產(chǎn)生一個(gè)新的空位(high指向的)?,F(xiàn)在從左向右移動(dòng)low,尋找大于分割元素的數(shù)。在找到時(shí),把這個(gè)找到的數(shù)復(fù)制給high指向的空位。重復(fù)執(zhí)行此過(guò)程,交替操作low和high,直到兩者在數(shù)組中間的某處相遇時(shí)停止。此時(shí),兩個(gè)標(biāo)記都指向空位,只要把分割元素復(fù)制給空位就可以了。然后,定義名為quicksort的遞歸函數(shù),調(diào)用split函數(shù)進(jìn)行快速排序。完整程序如下:
#include<stdio.h>
#defineN10
intmain(void)
{
voidquicksort(inta[],intlow,inthigh);
inta[N],i;
printf(“Enter%dnumberstobesorted:”,N); /*輸入*/
for(i=0;i<N;i++)
scanf(“%d”,&a[i]);
quicksort(a,0,N-1);
/*快速排序*/
printf(“Insortedorder:”); /*輸出*/
for(i=0;i<N;i++)
printf("%d",a[i]);
printf(“\n”);
return0;
}
voidquicksort(inta[],intlow,inthigh)
{
intmiddle;
intsplit(inta[],intlow,inthigh);
if(low>=high)return; /*結(jié)束*/
middle=split(a,low,high); /*分割*/
quicksort(a,low,middle-1); /*遞歸*/
quicksort(a,middle+1,high);
}
intsplit(inta[],intlow,inthigh)
{
intpart_element=a[low];
for(;;){
while(low<high&&part_element<=a[high])
high--;
if(low>=high)break;
a[low++]=a[high];
while(low<high&&a[low]<=part_element)
low++;
if(low>=high)break;
a[high--]=a[low];
}
a[high]=part_element;
returnhigh;
}雖然快速排序算法是目前效率最高的一種排序算法,但還可以從以下三個(gè)方面考慮對(duì)其進(jìn)行改進(jìn):
(1)改進(jìn)分割算法。不選擇數(shù)組中的第一個(gè)元素作為分割元素,而是取第一個(gè)元素、中間元素和最后一個(gè)元素的中間值作為分割元素。分割過(guò)程本身也可以加速,特別是在兩個(gè)while循環(huán)中要避免測(cè)試low?<?high。
(2)采用不同的方法進(jìn)行小數(shù)組排序。不再遞歸地使用快速排序法對(duì)所有分割后的小數(shù)組進(jìn)行排序,針對(duì)小數(shù)組(比方說(shuō),擁有的元素?cái)?shù)量少于25個(gè)的數(shù)組)更好的方法是采用較為簡(jiǎn)單的方法(如插入排序)。
(3)使得快速排序非遞歸。雖然快速排序本質(zhì)上是遞歸算法,并且遞歸格式的快速排序是最容易理解的,但是實(shí)際上若去掉遞歸會(huì)更高效。
2.選擇排序
選擇排序包括簡(jiǎn)單選擇排序和堆排序(heapsort),這里只討論簡(jiǎn)單選擇排序。
簡(jiǎn)單選擇排序的基本思想是:每一趟從待排序的數(shù)據(jù)元素中選出最小(或最大)的一個(gè)元素,順序放在已排好序的數(shù)列的最后,直到全部待排序的數(shù)據(jù)元素排完。選擇排序是不穩(wěn)定的排序方法
【例7.22】輸入10個(gè)整數(shù)并用選擇排序法將它們按從大到小的順序排序。
程序如下:
main()
{
inti,j,p,q,s,a[10];
printf(“\ninput10numbers:\n”);
for(i=0;i<10;i++)
scanf(“%d”,&a[i]);
for(i=0;i<10;i++){
p=i;q=a[i];
for(j=i+1;j<10;j++)
if(q<a[j]){p=j;q=a[j];}
if(i!=p){
s=a[i];
a[i]=a[p];
a[p]=s;
}
printf(
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 合同范本合資
- 醫(yī)院線路驗(yàn)收合同范本
- app商城合作合同范本
- 南門小學(xué)租房合同范本
- 架子班組勞務(wù)分包合同范本
- 合作建設(shè)開發(fā)合同范本
- 口罩機(jī)居間合同范本
- 農(nóng)村自建車庫(kù)合同范本
- 豐臺(tái)區(qū)供暖安裝合同范本
- 卡車賣買合同范本
- 基礎(chǔ)模塊2Unit 8 Green Earth reading課件
- 某發(fā)電公司安全風(fēng)險(xiǎn)辨識(shí)分級(jí)管控與隱患排查治理匯編
- 啟封密閉、排放瓦斯專項(xiàng)辨識(shí)
- 盤扣式鋼管腳手架驗(yàn)收表
- EPC項(xiàng)目設(shè)計(jì)管理實(shí)施策劃書
- von frey絲K值表完整版
- 人教版四年級(jí)數(shù)學(xué)下冊(cè)第一單元提升測(cè)試卷(Word版含答案)
- 內(nèi)部審核檢查表人力資源部
- GB/T 3452.4-2020液壓氣動(dòng)用O形橡膠密封圈第4部分:抗擠壓環(huán)(擋環(huán))
- GA/T 1310-2016法庭科學(xué)筆跡鑒定意見規(guī)范
- 西南交通大學(xué)文科建設(shè)發(fā)展綱要
評(píng)論
0/150
提交評(píng)論