《C語(yǔ)言程序設(shè)計(jì) 》課件第7章_第1頁(yè)
《C語(yǔ)言程序設(shè)計(jì) 》課件第7章_第2頁(yè)
《C語(yǔ)言程序設(shè)計(jì) 》課件第7章_第3頁(yè)
《C語(yǔ)言程序設(shè)計(jì) 》課件第7章_第4頁(yè)
《C語(yǔ)言程序設(shè)計(jì) 》課件第7章_第5頁(yè)
已閱讀5頁(yè),還剩124頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(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ì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論