《程序設計與C語言》課件第8章_第1頁
《程序設計與C語言》課件第8章_第2頁
《程序設計與C語言》課件第8章_第3頁
《程序設計與C語言》課件第8章_第4頁
《程序設計與C語言》課件第8章_第5頁
已閱讀5頁,還剩240頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領

文檔簡介

第8章結(jié)構(gòu)體、共用體及枚舉類型8.1結(jié)構(gòu)體類型8.2動態(tài)數(shù)據(jù)結(jié)構(gòu)8.3共用體8.4位段8.5枚舉類型習題88.1結(jié)構(gòu)體類型8.1.1結(jié)構(gòu)體變量的定義及初始化

1.結(jié)構(gòu)體類型的定義要定義結(jié)構(gòu)體變量,首先要定義結(jié)構(gòu)體類型。結(jié)構(gòu)體類型定義的一般形式是:

struct[〈結(jié)構(gòu)名〉]

{〈成員表〉;

};〈成員表〉∷=〈分量1〉;[〈分量2〉;…]

〈分量〉∷=〈類型標識符〉〈分量名〉其中,符號“∷=”表示“定義為”,方括號中的內(nèi)容是可選的。例如語句

structdate{intyear;intmonthintday;};就定義了一個表示日期的結(jié)構(gòu)體類型,類型名為structdate。它的三個分量的類型均為整型。對結(jié)構(gòu)體來說,分量的類型可以互不相同,這是它與數(shù)組的區(qū)別。數(shù)組也是構(gòu)造類型,但它要求各元素具有相同的類型。再如

structstudent{ unsignednum; charname[10];

intage; loatscore;};定義了一個學生的結(jié)構(gòu)體類型,名字為structstudent,它有4個分量,類型各不相同。結(jié)構(gòu)體類型可以嵌套定義,即結(jié)構(gòu)體的分量類型是另一個結(jié)構(gòu)體類型。以下兩種情況都可以定義嵌套的結(jié)構(gòu)體類型:

(1)兩個結(jié)構(gòu)體類型的定義是分離的,后者可以把前者作為其分量類型。比如上面已經(jīng)定義了日期類型,則可以用它來定義學生類型:

structstudent{unsignednum;charname[10];intage;floatscore;structdatebirthday;};

(2)還可以在一個結(jié)構(gòu)體內(nèi)部直接嵌套定義:

structstudent{unsignednum;charname[10];intage;floatscore;struct{intyear;intmonth;intday;}birthday;}

注意:①結(jié)構(gòu)體類型不能遞歸定義,即分量的類型不能是正在定義的結(jié)構(gòu)體類型。如:

structwrong{inti;structwrongw;};這樣的定義是錯誤的。②定義結(jié)構(gòu)體類型時,常犯的錯誤是忽略了最后的分號。

2.結(jié)構(gòu)體變量的定義在定義了類型名之后,就可以定義該類型的變量了。定義結(jié)構(gòu)體變量的方法有三種:

(1)如結(jié)構(gòu)體類型已定義好,則可以用來定義變量。如:

structdatedate1,date2;structstudentstu1,stu2;

注意:在使用結(jié)構(gòu)體類型名時,初學者往往會忽略保留字struct,其實structdate和structstudent都是一個統(tǒng)一的整體,二者缺一不可。

(2)定義結(jié)構(gòu)類型的同時直接定義變量,如

structdate { intyear; intmonth; intday; } date1,date2;

(3)定義結(jié)構(gòu)體類型的同時定義變量,但沒有結(jié)構(gòu)名。第(2)和(3)種的差別在于:第(2)種方法既定義了類型名又定義了變量,以后需要時還可以繼續(xù)定義新的變量,而第(3)種就不能再定義新的變量了,因為它沒有結(jié)構(gòu)名。

3.結(jié)構(gòu)體變量賦初值結(jié)構(gòu)體變量可以在定義時賦初值,如語句

structstudentstu1,stu2={63001,″zhang″,18,642.5};就對結(jié)構(gòu)體變量stu2進行了初始化,實際上是用右邊的值對stu2各分量進行初始化,因此提供的初值必須和相應分量的類型一致。兩個相同類型的結(jié)構(gòu)體變量之間可以進行賦值操作。如:

stu1=stu2;則使stu1的各分量具有了和stu2各分量一樣的值。

4.結(jié)構(gòu)體指針變量的定義除了定義結(jié)構(gòu)體變量之外,還可定義結(jié)構(gòu)體指針變量。如:

structstudentstu1,*p;定義了結(jié)構(gòu)體類型指針p。像其他類型的指針一樣,結(jié)構(gòu)體指針只有和某個結(jié)構(gòu)體變量發(fā)生了聯(lián)系,即得到了結(jié)構(gòu)體變量的首地址之后才能被使用。如:

p=&stu1;就把stu1的首地址,即第一個分量的地址賦給了p,p于是指向這個結(jié)構(gòu)體變量,如下圖所示。這之后對stu1和對*p的操作效果都是一樣的。stu1pnumnameagescore

5.結(jié)構(gòu)體變量的內(nèi)存分配結(jié)構(gòu)體變量由各分量組成。各分量分配內(nèi)存的次序和規(guī)則與普通變量有所不同。如:structstudent{charname[7];intage;charsex;floatscore;}stu,*p=&stu;則其內(nèi)存分配情況如圖8-1所示。圖8-1結(jié)構(gòu)體變量各分量的內(nèi)存分配情況從圖8-1中可以看出:

(1)結(jié)構(gòu)體變量中各分量內(nèi)存分配的情況是:按照各分量出現(xiàn)的先后次序,先出現(xiàn)的分量在上面,地址小;后出現(xiàn)的分量在下面,地址大。

(2)數(shù)組分量中,下標小的元素在上面,地址??;下標大的元素在下面,地址大。

(3)各分量之間的關(guān)系依系統(tǒng)的不同而有所不同。對TurboC來說,各分量之間沒有空洞,即不要求各分量按整字邊界存放,它們之間是緊湊的。因此,當用sizeof運算符求結(jié)構(gòu)體變量的大小時,其值等于各分量實際字節(jié)數(shù)之和,此處有:sizeof(stu)=14。而對VisualC++而言,要求各分量按整字邊界存放,這樣在各分量之間就有可能存在空洞,因此在用sizeof運算符求結(jié)構(gòu)體變量的大小時,必須將這些空洞計算進來,此處有:sizeof(stu)=20。由此可知,在求結(jié)構(gòu)體變量的大小時,必須首先明確是在什么系統(tǒng)中進行的。8.1.2結(jié)構(gòu)體數(shù)組及結(jié)構(gòu)體分量的引用

1.結(jié)構(gòu)體數(shù)組一個結(jié)構(gòu)體變量可以處理一個對象,如果有多個對象,則需要多個結(jié)構(gòu)體變量,這時應該用結(jié)構(gòu)體數(shù)組來處理多個同類型的對象。例如,定義一個產(chǎn)品類型的數(shù)組prod:

structproduct{unsignedlongno;charname[15];intnum;floatprice;}prod[3];定義結(jié)構(gòu)體變量的其他兩種方法也可以用來定義結(jié)構(gòu)體數(shù)組。對結(jié)構(gòu)體數(shù)組可以初始化,例如

structproductprod[3]={{112346,″football″,56,284.5},{112347,″basketball″,108,256},{112348,″valleyball″,35,96.4}};其邏輯結(jié)構(gòu)如圖8-2所示。圖8-2結(jié)構(gòu)體數(shù)組的邏輯結(jié)構(gòu)這個結(jié)構(gòu)像是二維數(shù)組,但它不是真正的數(shù)組,它沒有行地址和列地址之說,因此對它用指針進行操作時也就沒有所謂行指針和列指針的問題,只有一種指向結(jié)構(gòu)體的指針。例如,若定義結(jié)構(gòu)體指針變量p:

structproduct*p;則經(jīng)過賦值運算“p=prod;”之后,就使p指向了prod數(shù)組的第1個元素prod[0]。p++后指向prod[1],即沿垂直方向向下走一步,指向下一個結(jié)構(gòu)體,而不能說指向下一行。并且它也只能沿著垂直方向前進,而不能沿水平方向前進。至于水平方向的引用則涉及到對結(jié)構(gòu)體分量引用的問題。

2.對結(jié)構(gòu)體分量的引用對結(jié)構(gòu)體分量的引用有三種方法:用點運算符引用;用指向運算符引用;對數(shù)組元素的分量用下標加點或指向運算符引用。下面分別加以說明。

(1)用點運算符引用結(jié)構(gòu)體變量的分量的方法,有兩種引用形式:

〈結(jié)構(gòu)體變量名〉.〈分量名〉 (*〈結(jié)構(gòu)體指針〉).〈分量名〉即在結(jié)構(gòu)體變量和其分量名之間加一個點運算符。例如:

structproductprod,*p=∏則

prod.num=35; /*等價于(*p).num=35;*/ strcpy(,″football″);就是對結(jié)構(gòu)體變量prod的分量進行賦值的運算。這時prod.num(或(*p).num)、作為一個獨立的變量使用,可以直接進行輸入/輸出操作。

【例8-1】對結(jié)構(gòu)體分量的引用。#include<stdio.h>structproduct{unsignedlongno;charname[15];intnum;floatprice;};main(){structproductprod;prod.no=117364;prod.num=46;prod.price=287.5scanf(″%s″,);printf(″%lu,%s,%d,%f\n″,prod.no,,prod.num,prod.price);return0;}運行輸出:

football↙

117364,football,46,287.5

注意:因為name分量是字符數(shù)組,所以不能用賦值語句直接賦值,只能用字符串處理函數(shù)strcpy或用scanf函數(shù)的控制符“%s”控制輸入。

(2)用指向運算符引用結(jié)構(gòu)體指針所指對象的分量的方法,是用結(jié)構(gòu)體指針處理結(jié)構(gòu)體的常用形式,其引用形式為:

〈結(jié)構(gòu)體指針變量〉->〈分量名〉指向運算符由兩個字符“-”和“>”組成,它是一個整體,中間沒有空格。例如:

p->no=117368;strcpy(p->name,″basketball″);

【例8-2】用指針重做例8-1。#include<stdio.h>structproduct{unsignedlongno;charname[15];intnum;floatprice;};main(){structproductprod,*p;p=∏scanf(″%lu%s%d%f″,&p->no,p->name,&p->num,&p->price);printf(″%lu,%s,%d,%f\n″,p->no,p->name,p->num,p->price);return0;}運行輸出:

117364valleyball75197.6↙

117364valleyball75197.6輸入時應注意,數(shù)字和后面的字符串之間可以不留空格,編譯器會自動識別數(shù)字的終結(jié),但字符串和后面的數(shù)字之間必須有空格,否則編譯器會把數(shù)字也當作字符看待。

(3)用下標加點運算符引用結(jié)構(gòu)體數(shù)組元素的分量的方法,其引用形式為:

〈數(shù)組名〉[〈下標〉].〈分量名〉

注意:下標和數(shù)組名緊密相連,不可分離,不能把下標放在分量名后面。例如:

structproductprod[3];則

prod[2].price=78.5;是正確的引用,而prod.price[2]則是錯誤的寫法。

【例8-3】建立和輸出有3個元素的產(chǎn)品結(jié)構(gòu)體數(shù)組,并輸出價格最高的產(chǎn)品的所有信息。#include<stdio.h>structproduct{unsignedlongno;charname[15];intnum;floatprice;struct{intyear,month,day;}}outdate;}prod[3];main(){inti,j;floatmax=0;structproduct*p=prod;puts(″Inputprod[3]:\n″);for(i=0;i<=2;i++)scanf(″%lu%s%d%f%d%d%d″,&prod[i].nu,prod[i].name,&prod[i].num,&prod[i].price,&prod[i].outdate.year,&prod[i].outdate.month,&prod[i].outdate.day);printf(″Theprod[3]arrayis:\n″);for(i=0;i<=2;i++){print(″%lu,%s,%d,%.2f,&d/%d/%d\n″,p->no,p->name,p->num,p->price,p->outdate.year,p->outdate.month,p->outdate.day);p++;printf(″\n″);}for(i=0;i<=2;i++)if(prod[i].price>max){max=prod[i].price;j=i;}printf(″Elementhavinghighestprice:\n″);printf(″%lu,%s,%d,%.2f,%d,%d,%d\n″,prod[j].no,prod[j].name,prod[j].num,prod[j].price,prod

[i].outdate.year,prod[j].outdate.month,prod[j],outdate.day);return0;}運行輸出:

Inputprod[3]:

11111aaaaa8999.22001119↙

22222bbbbb76100.4200218↙33333ccccc96187200284Theprod[3]arrayis:

11111aaaaa8999.202001/11/922222bbbbb76100.402002/1/833333ccccc96187.002002/8/4Elementhavinghighestprice:33333ccccc96187.002002/8/4本例中prod[3]是一個嵌套的結(jié)構(gòu)體類型數(shù)組,其中出廠日期分量outdate是一個結(jié)構(gòu)體類型。在對嵌套的結(jié)構(gòu)體分量進行引用時,必須連續(xù)使用點運算符,以達到分量的最底層,這時才可以對各分量進行輸入/輸出操作。比如第i個元素的出廠年份的表示為:prod[i].outdate.year,這個序列是個整體,相當于一個整型變量,可以對它進行讀/寫。

(4)用指向運算符也可以引用結(jié)構(gòu)體數(shù)組元素的分量,因為對結(jié)構(gòu)體數(shù)組可以用指針進行處理。例如有定義:

structproductprod[3],*p;令p=prod,則p指向數(shù)組prod的第1個元素,p++指向下一個元素,每個元素又是結(jié)構(gòu)體,仍要用“->”運算符求其分量,如圖8-3所示。用指針來引用結(jié)構(gòu)體分量時,要注意“->”運算符的優(yōu)先級最高,它把前后兩部分連成一個不可分割的整體,因此,p->num++等價于(p->num)++,即先取出p所指結(jié)構(gòu)體的num分量的當前值,然后對它加1;++p->num等價于++(p->num),即對num分量加1;(++p)->num是先把p移向數(shù)組的下一個元素,再求該元素的num分量;(p++)->num是先把p所指結(jié)構(gòu)的num分量取出,再把p向下移一個元素。為了加深對結(jié)構(gòu)體指針和結(jié)構(gòu)體數(shù)組的理解,我們可以分析下面的程序。圖8-3結(jié)構(gòu)體數(shù)組的指針處理

【例8-4】分析下面程序的輸出結(jié)果。#include<stdio.h>structsinl{char*s;inti;structsinl*slp;};main(){staticstructsinla[]= {{″abcd″,1,a+1}, {″efgh″,2,a+2}, {″ijkl″,3,a}};structsinl*p=a;inti; printf(″a[0].s=%s\tp->s=%s\ta[2].slp->s=%s\n\n″,a[0].s,p->s,a[2].slp->s);for(i=0;i<2;i++)printf(″--a[%d].i=%d\t++a[%d].s[3]=%c\n″,i,--a[i].i,i,++a[i].s[3]);

printf(″++(p->s)=%s\ta[(++p)->i].s=%s\t″″a[--(p->slp->i)].s=%s\n″,++(p->s),

a[(++p)->i].s,a[--(p->slp->i)].s);return0;}運行輸出:

a[0].s=abcdp->s=abcda[2].slp->s=abcd--a[0].i=0++a[0].s[3]=e--a[1].i=1++a[1].s[3]=i++(p->s)=fgia[(++p)->i].s=abcea[--(p->slp->i)].s=abce程序中定義了一個結(jié)構(gòu)體數(shù)組a并初始化。從初始化的數(shù)據(jù)看有三個結(jié)構(gòu)體。圖8-4畫出了這三個結(jié)構(gòu)體中指針的指向。圖8-4結(jié)構(gòu)體中指針的指向在定義的結(jié)構(gòu)體中,分量slp是指向自身結(jié)構(gòu)的指針,這種結(jié)構(gòu)稱為自引用結(jié)構(gòu)。slp又稱為“鏈接”,它能夠把一個structsinl結(jié)構(gòu)體與另一個同樣的結(jié)構(gòu)體鏈接在一起。因為slp是指針,所以這不是遞歸定義。結(jié)構(gòu)體中有一個分量的名字為i,而在主函數(shù)中,i又被定義成一個新的整型變量,兩者是否會沖突?答案是不會,因為它們所處的地方不同,作用也不同。①由圖8-3可知,a[0]的s分量是指向字符串的指針;p->s為p所指對象的s分量,即a[0]的s分量,是一個指針;a[2].slp->s為a[2]的slp分量所指對象的s分量,也即a[0]的s分量。這三種表示是等價的,因而輸出也相同,為“abcd”。②因為--a[i].i等價于--(a[i].i),即以a[i]的i分量的值減1作為輸出結(jié)果,所以--a[0].i=0,--a[1].i=1,于是a[0].i=0,a[i].i=1。③因為++a[i].s[3]=++(a[i].s[3]),s是指向字符串中第一個字符的指針,s+3為指向該串第3+1個字符的指針,又因為s[3]=*(s+3),即s[3]為該串第3+1個字符,所以++a[i].s[3]表示a[i]的s分量指向的字符串中的第3+1個字符加1(即其后繼字符),所以++a[0].s[3]=e,++a[1].s[3]=i,于是a[0].s指向“abce”,a[1].s指向“efgi”。在下面的輸出中,以TurboC對函數(shù)參數(shù)由右向左進行求值的順序,先計算并輸出a[--(p->slp->i)].s,然后是a[(++p)->i].s,最后是++(p->s),且左邊的求值受右邊求值的影響。④求a[--(p->slp->i)].s:這時p指向a[0],p->slp->i,即a[1].i,它的值已變?yōu)?,再對它進行自減運算得a[1].i=0,于是a[0].s指向“abce”。⑤求a[(++p)->i].s:因p指向a[0],則++p使p指向a[1],而a[1]的i分量的值已變?yōu)?,則a[(++p)->i].s仍是求a[0].s所指字符串,即“abce”。⑥求++(p->s):因此時p已指向a[1],p->s即為a[1]的s分量,它指向字符串“efgi”的第1個字符e,則++(p->s)指向“efgi”的第2個字符f,故輸出為“fgi”。

注意:在循環(huán)語句中,a[i].i中的兩個i代表不同的對象,方括號中的i是循環(huán)控制變量,代表數(shù)組元素的下標,而小數(shù)點后面的i則是結(jié)構(gòu)體的分量名。

3.二維結(jié)構(gòu)體數(shù)組二維結(jié)構(gòu)體數(shù)組和其他類型的二維數(shù)組一樣,由行和列組成,只不過它的每個元素是一個結(jié)構(gòu)體,每個結(jié)構(gòu)體又有自己的分量,因此,在對二維結(jié)構(gòu)體數(shù)組賦初值和進行存取的過程中,必須考慮到行、列及分量等特點。設有定義structcid{charch;inti;doublex;}a[3][3];則結(jié)構(gòu)體類型cid有三個分量,二維數(shù)組a有3行,每行有3列,共有9個元素,即有9個結(jié)構(gòu)體。它的組織形式如圖8-5所示。圖8-5二維結(jié)構(gòu)體數(shù)組在對二維數(shù)組賦初值時,為了清晰起見,應適當?shù)厥褂美ㄌ?,以便于把每行、每個元素都清楚地表示出來。例如:structcida[3][3]={{{′a′,1,1.1},{′b′,2,2.2},{′c′,3,3.3}},{{′d′,4,4.4},{′e′,5,5.5},{′f′,6,6.6}},{{′g′,7,7.7},{′h′,8,8.8},{′i′,9,9.9}},}在賦初值時應注意,每行之間、每列之間及結(jié)構(gòu)體的分量之間都不能留有空洞,或簡單地講,不能連續(xù)地出現(xiàn)兩個逗號,即在兩個逗號之間必須有具體內(nèi)容。但在每對括號內(nèi)部,后面的部分可以省略,該處的變量自動具有初值:字符型數(shù)據(jù)的初值為空字符,數(shù)值型數(shù)據(jù)的初值為零。要引用二維數(shù)組中元素的分量,必須在數(shù)組名的后面帶兩個下標,后跟點運算符加分量名。比如要引用上述定義中的字符′f′,則其表示為a[1][2].ch,對其中元素2.2的引用是a[0][1].x。若數(shù)組名只帶一個下標,如a[1],則它表示第2行第1個元素的地址,此時對′f′的引用應表示成(*(a[1]+2)).ch。注意:點運算符的優(yōu)先級高于間接引用運算符*,所以必須把*(a[1]+2)用括號括起來。

【例8-5】設有I個班,每班有J名學生,每個學生有N個成績,請輸入學生的姓名和4科成績,并計算每個學生的平均分,所有學生全部成績的平均分、最高分和最低分。

編程思路:一個學生的信息用一個結(jié)構(gòu)體描述,所有班、所有學生可用二維數(shù)組加以組織,因此這是一個二維結(jié)構(gòu)體數(shù)組,可用上面敘述的方法加以處理。程序如下:#include<stdio.h>#defineI2#defineJ3#defineN4structstudent{charname[10];floatscore[N];floatave;}a[I][J];main(){inti,j,n;floatmax,min,average,sum,sumi;max=average=sum=0;min=100;for(i=0;i<I;i++)for(j=0;j<J;j++){sumi=0;printf(″Inputaname:″);scanf(″%s″,&a[i][j].name);printf(″Input%dscores:″,N):for(n=0;n<N;n++){scanf(″%f″,&a[i][j].score[n]);if(a[i][j].score[n]>max)max=a[i][j].score[n];if(a[i][j].score[n]<min)min=a[i][j].score[n];sum+=a[i][j].score[n];sumi+=a[i][j].score[n];}a[i][j].ave=sumi/N;}for(i=0;i<I;i++){printf(″\n\nclass%d:\n″,i+1);printf(″Namescore1score2score3score4average\n″);for(j=0;j<J;j++){printf(″%-5s″,(*(a[i]+j)).name);for(n=0;n<N;n++)printf(″%.1f″,(*(a[i]+j)).score[n]);printf(″%.1f\n″,(*(a[i]+j)).ave);}}average=sum/(I*J*N);printf(″\nmax=%.1f\nmin=%.1f\ntotalaverage=%.1f\n\n″,max,min,average);return0;}運行輸出:Inputaname:zhaoInput4scores:88898768Inputaname:qianInput4scores:78899786Inputaname:sunInput4scores:89978659Inputaname:liInput4scores:89979668Inputaname:zhouInput4scores:87766989Inputaname:wuInput4scores:85839691class1:Namescore1score2score3score4averagezhao88.089.087.068.083.0qian78.089.097.086.087.5sun89.097.086.059.082.8class2:Namescore1score2score3score4averageli89.097.096.068.087.5zhou87.076.069.089.080.3wu85.083.096.091.088.8max=97.0min=59.0totalaverage=85.08.1.3結(jié)構(gòu)體變量和結(jié)構(gòu)體指針作參數(shù)結(jié)構(gòu)體變量和結(jié)構(gòu)體指針都可以作為函數(shù)的參數(shù)及函數(shù)的返回值。若形參和實參均為結(jié)構(gòu)體變量,則參數(shù)傳遞的是結(jié)構(gòu)體的拷貝,屬于函數(shù)的傳值調(diào)用。但這樣做既費時間又費空間。如果把形參定義成指針類型,就可以解決這兩方面的問題。這時實參傳遞的是結(jié)構(gòu)體變量的地址,函數(shù)中對形參的處理就是對實參的直接處理。下面的例子說明了這種情況。

【例8-6】求兩個復數(shù)的和與積。

編程思路:復數(shù)相加的公式為:(a+bi)+(c+di)=(a+c)+(b+d)i即兩個復數(shù)相加結(jié)果仍為一復數(shù),結(jié)果的實部為兩個復數(shù)的實部之和,結(jié)果的虛部為兩個復數(shù)的虛部之和。復數(shù)相乘的公式為:(a+bi)*(c+di)=(ac-bd)+(bc+ad)i復數(shù)可以設計成一個結(jié)構(gòu)體類型。復數(shù)相加與相乘用兩個函數(shù)表示。復數(shù)結(jié)構(gòu)體類型在各個函數(shù)中都要使用,因此把它放到所有函數(shù)之外,作為全局類型定義。

#include<stdio.h>structcomplex{floatre,im;};structcomplex*cadd(structcomplex*,structcomplex*,structcomplex*);structcomplexcmul(structcomplex,structcomplex);main(){structcomplexa,b,c,d,*pa=&a,*pb=&b;*pc=&c;printf(″Inputa.re=?,a.im=?\n″);scanf(″%f%f″,&a.re,&a.im);printf(″Inputb.re=?,b.im=?\n″);scanf(″%f%f″,&b.re,&b.im);pc=cadd(pa,&b,&c);d=cmul(a,b);printf(″sumof2complexnumber:\n″);printf(″c.re=%.1f,c.im=%.1f\n″,c.re,(*pc).im);printf(″\n\nmultipleof2complexnumber:\n″);printf(″d.re=%.1f,d.im=%.1f\n″,d.re,d.im);return0;}}structcomplex*cadd(structcomplex*x,structcomplex*y,structcomplex*t){(*t).re=(*x).re+(*y).re;(*t).im=(*x).im+(*y).im;returnt;}structcomplexcmul(structcomplexx,structcomplexy){structcomplexc;c.re=x.re*y.re-x.im*y.im;c.im=x.im*y.re+x.re*y.im;returnc;}運行輸出:

Inputa.re=?a.im=?23↙

Inputb.re=?b.im=?34↙sumof2complexnumber:c.re=5.0,c.im=7.0multipleof2complexnumber:d.re=-6.0,d.im=17.0對于cmul函數(shù),兩個參數(shù)都是結(jié)構(gòu)體類型,實參也是兩個結(jié)構(gòu)體變量,返回值也是結(jié)構(gòu)體類型。函數(shù)cadd有3個參數(shù),全是結(jié)構(gòu)體指針,實參有結(jié)構(gòu)體指針,也有結(jié)構(gòu)體變量的地址,它們都是等價形式。函數(shù)以一個形參t作為返回值,調(diào)用時把結(jié)構(gòu)體變量c的地址賦給形參t,則在函數(shù)中對t的處理也就是對實參c的處理。函數(shù)返回的t也被指向c的指針pc所接收。

討論:根據(jù)cadd函數(shù)的處理情況,能否去掉形參t,而把它作為函數(shù)體內(nèi)定義的指針變量呢?這是不允許的,因為作為臨時指針變量,在它和具體的結(jié)構(gòu)體建立聯(lián)系之前,它的指向是隨機的,對它指向的內(nèi)存空間的賦值有可能引起破壞性的后果。但是可以對cadd函數(shù)作如下變形:

voidcadd(structcomplex*x,structcomplex*y,structcomplex*t){(*t).re=(*x).re+(*y).re;(*t).im=(*x).im+(*y).im;}即函數(shù)中可以不要返回語句,因為對形參t的處理也是對實參的處理,所以這里可以用函數(shù)語句的形式對函數(shù)cadd進行調(diào)用。

cadd(pa,pb,pc);思考:cadd函數(shù)能作如下定義嗎?structcomplex*cadd(structcomplex*x,structcomplex*y){structcomplext,*p=&t;t.re=(*x).re+(*y).re;t.im=(*x).im+(*y).im;returnp;}

注意:函數(shù)中定義的變量都是內(nèi)部變量或臨時變量,它們只在函數(shù)內(nèi)部起作用,一旦到了函數(shù)外部就失去了作用,臨時為它開辟的內(nèi)存也被收回。

【例8-7】日期倒計時。計算今天距北京2008年奧運會開幕還剩多少天。編程思路:日期由年、月、日組成,可用結(jié)構(gòu)體表示。倒計時的計算由三部分組成:當年所余天數(shù)+下一年距開幕前一年的天數(shù)+開幕當年的天數(shù)。

(1)當年所余天數(shù)=當月所余天數(shù)+下個月至年底的天數(shù)。

·當月所余天數(shù)=當月總天數(shù)-當天號數(shù);

·下月至年底天數(shù)=各個月份的天數(shù)累加。

(2)下一年距開幕前一年的天數(shù)=各年天數(shù)累加。累加時閏年為366天,非閏年為365天。

(3)開幕當年的天數(shù)=開幕那月前數(shù)月的天數(shù)+開幕那天的號數(shù)。設北京奧運會開幕時間為2008年8月8日,可用宏定義表示具體數(shù)值,若改為其他日期,只需修改宏值即可。對當前日期的輸入,可以用一個函數(shù)實現(xiàn),函數(shù)的參數(shù)為一個指向結(jié)構(gòu)體的指針,函數(shù)調(diào)用時的實參為主調(diào)函數(shù)中定義的指針,在使用以前它已指向了一個結(jié)構(gòu)體變量。所以函數(shù)中對形參指針的操作,也就是對結(jié)構(gòu)體變量的操作。程序如下:#include<stdio.h>#include<dos.h>#defineYEAR2008#defineMON8#defineDAY8intdays[2][12]={{31,28,31,30,31,30,31,31,30,31,30,31},{31,29,31,30,31,30,31,31,30,31,30,31}};structdate{intda_year;intda_mon;intda_day;};main(){inti,l,sum=0;intleap(int);voidgetdate(structdate*);structdatetoday;structdate*p1=&today;getdate(p1);printf(″today:%d.%d.%d\n″,p1->da_year,p1->da_mon,p1->da_day);for(i=p1->da_year+1;i<=YEAR-1;i++)if(leap(i))sum+=366;elsesum+=365;l=leap(YEAR);for(i=0;i<MON-1;i++)sum+=days[1][i];sum+=DAY;sum+=days[l][p1->da_mon-1]-p1->da_day;for(i=p1->da_mon;i<=11;i++)sum+=days[leap(p1->da_year)][i];printf(″\nToBeijingOlympic,i1rest%ddays!\n\n″,sum);return0;}intleap(intm){if(m%4==0&&m%100!=0||m%400==0)return1;elsereturn0;}voidgetdate(structdate*p){printf(″Inputcurrentyear:\n″);scanf(″%d″,&p->da_year);printf(″Inputcurrentmonth:\n″);scanf(″%d″,&p->da_mon);printf(″Inputcurrentday:\n″);scanf(″%d″,&p->da_day);}運行輸出:Inputcurrentyear:2006↙

Inputcurrentmonth:7↙Inputcurrentday:20↙today:2006.7.20ToBeijingOlympic,ilrest750days!8.1.4類型名定義typedef在上面的例子中,我們定義了一個復數(shù)類型structcomplex,這是個不能分開的整體,利用這個類型名可以定義變量、函數(shù)的返回值等。但這個類型名很長,稍不留心就會出錯。如果程序中有很多的復數(shù)類型的變量和函數(shù)需要定義,書寫起來更是不勝其煩。能不能簡單一些呢?答案是肯定的。C語言提供了一種機制,利用保留字typedef就可以用一個簡單的名字來代替像structcomplex這樣的長序列。例如:

typedefstructcomplexCOMPLEX;則COMPLEX即是和structcomplex等價的類型名,可以用它定義變量:

COMPLEXa,b,c,*pa;這樣用起來就方便多了。用typedef說明類型名的一般形式如下:

typedef〈原類型名〉〈新類型名〉新類型名一般用大寫表示,以便與原名在性質(zhì)上區(qū)別開來,即它不是新創(chuàng)造的類型,而是原類型的代名詞或化身,它代表了原類型。原類型名可以是構(gòu)造類型,也可以是標準類型,如:

typedeffloatREAL;就為標準類型float起了個新名REAL。以后在程序中,原名和別名可以同時使用。如有語句

REALf1,f2;就定義了兩個浮點型的變量f1和f2。說明新類型的方法十分簡單,可按下列步驟進行:

(1)先定義原類型的變量。

(2)把變量名大寫,以示它為新類型名。

(3)在前面加上typedef保留字。例如:

structstudentstu;structstudentSTU;typedefstructstudentSTU;于是STU即成為structstudent的新名字,可用來定義變量了,如

STUstud1,stud2;

注意:在用新類型名定義變量時,新類型說明中的附加部分不能寫上,如

typedefintARRAY[10];則新類型名為ARRAY,它代表有10個整型元素的數(shù)組,可以用它來這樣定義數(shù)組:

ARRAYa,b;而不能寫成:

ARRAY[10]a,b;說明:用typedef說明新類型名的目的是為了簡化書寫,便于閱讀,這對簡化結(jié)構(gòu)體類型名尤為有用,應該學會使用。但不要把簡單的問題復雜化,比如要定義有10個整型元素的數(shù)組,完全可以寫成:

inta[10],b[10],c[10];這樣的定義相當直觀明了,大可不必先去定義個ARRAY,再用ARRAY來定義有10個元素的數(shù)組,那樣做既麻煩又違背了簡化程序的初衷。用typedef定義的新類型名不一定要大寫,小寫也可以,大寫是為了突出新類型名。8.2動態(tài)數(shù)據(jù)結(jié)構(gòu)到目前為止我們所使用的數(shù)據(jù)結(jié)構(gòu)如數(shù)組等,其大小是一開始就定義好的,在程序中不能改動,這對內(nèi)存的合理使用及某些操作非常不便。而動態(tài)數(shù)據(jù)結(jié)構(gòu)是一開始并不指定大小,可以隨需要不斷增加,不用時隨時取消的結(jié)構(gòu),如鏈表、堆棧、隊列、樹等,這些動態(tài)結(jié)構(gòu)在信息科學中非常有用。8.2.1動態(tài)分配內(nèi)存建立和維護動態(tài)數(shù)據(jù)結(jié)構(gòu)需要進行動態(tài)的內(nèi)存分配,即在程序執(zhí)行過程中可以動態(tài)地得到內(nèi)存和回收內(nèi)存。動態(tài)分配內(nèi)存的極限是計算機中可用的物理內(nèi)存空間。為實現(xiàn)動態(tài)分配內(nèi)存,C語言提供了幾個專用的函數(shù)和運算符,它們是函數(shù)malloc、calloc、free和運算符sizeof。

1.malloc函數(shù)該函數(shù)原型為:

void*malloc(unsignedsize);功能:在內(nèi)存中開辟size個字節(jié)大小的連續(xù)空間。返回值為該空間的起始地址。若分配不成功,則返回0值。

2.calloc函數(shù)

calloc函數(shù)的原型為:

void*calloc(unsignedn,unsignedsize);功能:在內(nèi)存中開辟n個大小為size個字節(jié)(共n×size字節(jié))的連續(xù)空間。返回值為該段空間的起始地址。若分配不成功,則返回0值。這兩個函數(shù)返回值的類型都是void*,稱為空類型或抽象類型的指針。它具有某個內(nèi)存空間的地址值,一般用作指針類型轉(zhuǎn)換時的過渡形式。如果想讓開辟的內(nèi)存空間中存放某種類型的數(shù)據(jù),就把void*強制轉(zhuǎn)換成指向該類型的指針,以滿足不同調(diào)用環(huán)境的需要。如

char*cp;

cp=(char*)malloc(100);這里用malloc函數(shù)開辟出100個字節(jié)的空間,用于存放字符,返回值為指向第一個字符的指針。注意:不經(jīng)過強制轉(zhuǎn)換,則開辟的內(nèi)存不可用。如定義:char*p;p=malloc(7);則編譯時會給出錯誤提示:cannotconvertfrom′void*′to′char*′,而定義為p=(char*)malloc(7);就正確了。

double*dp=(double*)calloc(10,sizeof(double));則共開辟出10×sizeof(double)個(即10×8=80個)字節(jié)的空間,返回的指針指向第1個double單元,如圖8-6所示。

注意:NULL和void*是不同的,NULL是空指針,即值為0的指針,它常用作某種標志。比如鏈表結(jié)尾處的結(jié)構(gòu)體的鏈接指針值為NULL,表示該指針不指向其他結(jié)構(gòu)體。圖8-6返回指針的指向

3.free函數(shù)

free函數(shù)的原型為:

voidfree(void*p);功能:釋放p所指的內(nèi)存空間,無返回值。以上三個函數(shù)的原型在<stdlib.h>頭文件中,因此使用它們時應把該頭文件包含進來。

【例8-8】編一函數(shù)strsave,它可接收一個字符串,然后動態(tài)地開辟一個能放得下這個字符串的內(nèi)存空間,把接收到的字符串復制到其中,并返回該空間的起始地址。#include<stdio.h>

#include<stdlib.h>

#include<string.h>char*strsave(char*);main(){char*str=″China″,*cp;cp=strsave(srt);printf(″str=%s,cp=%s\n″,str,cp);return0;}charstrsave*(char*s){char*p;if((p=(char*)calloc(strlen(s)+1,1))!=NULL)strcpy(p,s);returnp;}運行輸出:

str=China,cp=China標準函數(shù)calloc分配strlen(s)+1個大小為1的內(nèi)存空間。因為strlen函數(shù)統(tǒng)計字符串長度時不包含′\0′字符,但在復制字符串中還需要把′\0′加進去,所以分配空間時要加1。原calloc函數(shù)返回的是空類型指針,現(xiàn)在把它強制轉(zhuǎn)換成char型指針,再把該指針值賦給p,然后判斷p是否為NULL(0),若不為NULL,就調(diào)用字符串拷貝函數(shù)來完成拷貝工作。函數(shù)中開辟的內(nèi)存空間不會隨函數(shù)調(diào)用的結(jié)束而取消,因此p指針返回來的值是有意義的。相反,如果不開辟內(nèi)存空間,則p無所指向,不可使用。

4.sizeof運算符

sizeof運算符在本書第3章的3.3.6節(jié)中已有介紹,這里不再贅述。

【例8-9】學生的信息包括姓名、所在系名及三科成績。請輸入多個系的學生的信息,打印輸出指定系的學生的最高分和平均成績。#include<stdio.h>#include<string.h>#include<stdlib.h>typedefstruct{charname[20];char*dep;intscore[3];}STUTP;voidstuscore(STUTP*s,char*depart,int*max,float*ave,intm){intn,i;floatsum=0;n=0;while(m!=0){if(strcmp(s->dep,depart)==0){for(i=0;i<3;i++){ sum+=(*s).score[i]; if((*s).score[i]>*max) *max=(*s).score[i];}n++;}s++;m--;}*ave=sum/(3*n);printf(″In\′%s\′department,thereis%dstudents.\n″,depart,n);}voidmain(){STUTPx[50];inti=0,max,j;floatave;chardep[20],depbuf[20];while(1){puts(″Inputname:″);//scanf(″%s″,x[i].name);getchar();gets(x[i].name);if(strcmp(x[i].name,″***″)==0){printf(″Inputend!\n″);break;}puts(″Inputdepartment:″);x[i].dep=(char*)malloc(strlen(depbuf)+1);gets(x[i].dep);printf(″Input3scoresinteger:\n″);for(j=0;j<3;j++)scanf(″%d″,&x[i].score[j]);getchar();i++;}printf(″Youinput%dstudent!\n″,i);puts(″Inputdepartnametoconsider:″);gets(dep);max=0;ave=0.0;stuscore(x,dep,&max,&ave,i);printf(″max=%d,ave=%.1f\n″,max,ave);}程序說明:①程序中求最高分及平均分的工作由一個函數(shù)完成,函數(shù)的形參為指針,實參為主程序中定義的變量的地址,用這種方式可以從函數(shù)調(diào)用中獲取多個數(shù)值。②結(jié)構(gòu)體類型中的系名分量是指向字符的指針,不是字符數(shù)組,因此不能直接向它拷貝字符串。因為指針尚未指向具體的內(nèi)存空間,這就需要首先調(diào)用動態(tài)分配內(nèi)存的函數(shù)malloc分配內(nèi)存,并將此內(nèi)存空間的起始地址賦給該指針分量,然后再用它進行字符串輸入。③main函數(shù)中while循環(huán)的條件永遠是真,它的循環(huán)控制是由輸入的姓名字符串決定的,如果輸入的姓名是三個*號,則循環(huán)終止。④程序中使用typedef定義了一個類型名STUPT,這樣可以使程序簡潔。⑤在用scanf函數(shù)輸入姓名和分數(shù)之后,接著調(diào)用一個getchar函數(shù),目的是為了接收前面輸入操作中的回車符,為的是不影響下面的輸入。如果不用getchar吃掉前面留下來的回車符,則下面的輸入語句就會將此回車符作為輸入的內(nèi)容而出現(xiàn)錯誤。但是,如果用gets函數(shù)輸入字符串,則不需要再用getchar去消除輸入字符串時回車符的影響,因為gets會自動地將回車符變?yōu)樽址Y(jié)束標志附加到輸入字符串的末尾。運行輸出:Inputname:aaaInputdepartment:xxxInput3scoresinteger:809070Inputname:bbbInputdepartment:xxxInput3scoresinteger:4510055Inputname:cccInputdepartment:jsjxInput3scoresinteger:889977Inputname:dddInputdepartment:xxxInput3scoresinteger:12080100Inputname:***Inputend!Youinput4student!Inputdepartnametoconsider:xxxIn′xxx′department,thereis3students.max=120,ave=82.28.2.2鏈表鏈表是用鏈表指針連在一起的自引用結(jié)構(gòu)(稱為“結(jié)點”)的線性集合,如圖8-7所示。其中,head是指向鏈表第一個結(jié)點的指針,通過它來訪問鏈表。后面的結(jié)點是通過它前面結(jié)點中的鏈接指針來訪問的。鏈表的最后一個結(jié)點中的鏈接指針被置為NULL(畫成反斜杠以表示鏈尾)。鏈表中的結(jié)點是在需要時建立的,鏈表中的數(shù)據(jù)是動態(tài)存儲的。圖8-7鏈表的結(jié)構(gòu)我們可以把動態(tài)的鏈表和靜態(tài)的數(shù)組作一對比,以說明它們的特點。

(1)在數(shù)據(jù)元素的個數(shù)不可預知時,使用鏈表是合適的,因為可在需要時增加或減少鏈表中結(jié)點的個數(shù);數(shù)組是在編譯時分配內(nèi)存的,其大小是不可改變的。

(2)當數(shù)組定義得很大以備不時之需時會造成空間的浪費;鏈表隨用隨增,不會造成空間的浪費。

(3)對于插入和刪除操作,使用數(shù)組費時費力,而使用鏈表卻可以方便地在合適的位置插入和刪除結(jié)點,只要把有關(guān)結(jié)點的鏈接指針修改一下即可。

(4)數(shù)組中的元素在內(nèi)存中是連續(xù)存放的,根據(jù)相對于數(shù)組的起始位置可以計算出數(shù)組元素的地址,所以可以立即訪問到任意位置的數(shù)組元素;鏈表中的結(jié)點不能被立即訪問到,因為鏈表中的結(jié)點在邏輯上是連續(xù)的,但在內(nèi)存中是不連續(xù)的。雖然從總體上說,動態(tài)分配內(nèi)存能節(jié)省空間,但每個結(jié)點中的指針也要占用存儲空間,并且動態(tài)分配內(nèi)存也需要一些函數(shù)調(diào)用的開銷。下面我們研究鏈表的建立、插入、刪除及輸出等操作。

1.建立鏈表首先定義鏈表中結(jié)點的類型,它應該是一個自引用的結(jié)構(gòu)體。如

structnode{intdata;structnode*next;};typedefstructnodeNode;Node為新類型名。所定義的結(jié)構(gòu)體中有兩個分量,形成兩個域:數(shù)值域和指針域。對鏈表進行操作,需要三個指針:指向鏈表頭的指針head,指向當前結(jié)點的指針p1,指向當前結(jié)點前一結(jié)點的指針p2。先建立只有一個結(jié)點的鏈表,使head、p1、p2都指向它,如圖8-8所示。其操作步驟如下:

(1)產(chǎn)生一個結(jié)點,用p1指向它:

p1=(Node*)malloc(sizeof(Node));

(2)把p1賦給head和p2:p2=head=p1。

(3)對新結(jié)點的數(shù)據(jù)域輸入數(shù)據(jù),而把其指針域置為NULL。圖8-8鏈表的建立下面建立只有兩個結(jié)點的鏈表,即把第二個結(jié)點連到第一個結(jié)點之后作為鏈表尾,如圖8-9所示。要達到這樣的格局,需要進行如圖8-9所示的五步操作:①用p1指向新產(chǎn)生的結(jié)點:

p1=(Node*)malloc(sizeof(Node));②把新結(jié)點的指針域置空:

p1->next=NULL;③輸入新結(jié)點的數(shù)值域:

scanf(″%d″,&p->data);④把新結(jié)點連到鏈表尾部:

p2->next=p1;圖8-9建立兩個結(jié)點的鏈表⑤讓p2也指向新結(jié)點:

p2=p1;以后再加入新結(jié)點時,操作與此類似,但沒有必要每產(chǎn)生一個新結(jié)點都將其指針域置為NULL,而完全可以在最后一個結(jié)點中實行??梢园演斎霐?shù)值0作為鏈表建立的結(jié)束。數(shù)值域為0的結(jié)點不在鏈表內(nèi)。于是可寫出如下函數(shù):

Node*create(){Node*h=NULL,*p1,*p2;printf(″Inputintegertocreatealist,0toend:\n″);p1=(Node*)malloc(sizeof(Node));scanf(″%d″,&p1->data);if(p1->data!=0)h=p1;

while(p1->data!=0){p2=p1;p1=(Node*)malloc(sizeof(Node));scanf(″%d″,&p1->data);p2->next=p1;}p2->next=NULL;returnh;}循環(huán)體內(nèi)的操作是在當前結(jié)點的數(shù)值域不為0時才讓p2指向它。如當前結(jié)點的數(shù)值域為0,則不讓p2指向它,那么p2所指的結(jié)點就是最后一個結(jié)點,因此把它的next域置為NULL。雖然在循環(huán)體中進行過p2->next=p1的操作,但在循環(huán)體之后通過p2->next=NULL又把數(shù)值部分為0的那個結(jié)點從表中摘除了。這個函數(shù)的參數(shù)為空,返回值為指向結(jié)構(gòu)體的指針。

2.輸出鏈表當鏈表的頭指針為NULL時說明鏈表是空的,不采取行動。只有當鏈表非空時才從鏈表頭部開始,輸出一個結(jié)點的值,然后移動指針,再輸出下一個結(jié)點的值……直至表尾結(jié)束。可用下面的函數(shù)完成此項功能:voidprintList(Node*h){Node*p;p=h;if(h==NULL)printf(″Listisempty!\n\n″);else{while(p!=NULL){printf(″%d->″,p->data);p=p->next;}printf(″Null\n\n″);}}在函數(shù)體內(nèi)定義了一個工作指針p,起流動哨的作用,在輸出它所指結(jié)點的數(shù)值域之后,它就再向后移一位以指向下一個結(jié)點。這是由指針傳遞操作p=p->next來完成的。這個函數(shù)以結(jié)構(gòu)體指針作參數(shù),不返回值。

3.插入結(jié)點在一個鏈表中插入結(jié)點,首先要確定插入的位置,這里要考慮幾種情況:

(1)空表情況。

(2)插在表頭。

(3)插在表中。

(4)插在表尾。完成該功能的函數(shù)中使用了三個工作指針:newp,指向要被插入的結(jié)點;p1,指向當前結(jié)點;p2,指向當前結(jié)點的前一結(jié)點。這里設該鏈表已經(jīng)排序且按升序插入結(jié)點,則從鏈表的頭部開始,只要指向當前結(jié)點的指針p1不空且要插入的結(jié)點的數(shù)值又比當前結(jié)點的數(shù)值大,就繼續(xù)向后查找合適的位置,向后移動的方法是修改p1和p2的值。該函數(shù)如下:Node*insert(Node*h,intvalue){Node*newp,*p1,*p2;newp=(Node*)malloc(sizeof(Node));if(newp!=NULL){newp->data=value;newp->next=NULL;p2=Null;p1=h;while(p1!=Null&&value>p1->data){p2=p1; /*移到…*/p1=p1→next; /*下一結(jié)點*/}if(p2==NULL) /*插在表頭*/{newp->next=h;h=newp;}else{p2->next=newp;newp->next=p1;}}elseprintf(″%dnotinserted,Nomemoryavailable\n″,value);returnh;}該函數(shù)返回一個指向結(jié)構(gòu)體的指針,其參數(shù)為一個鏈表的頭指針和要插入的數(shù)值,最后返回的仍然是鏈表的頭指針,但鏈表在函數(shù)調(diào)用的過程中發(fā)生了變化。我們以圖示來說明插入結(jié)點的操作。

(1)結(jié)點插在表頭。設原頭結(jié)點數(shù)值為8,把數(shù)值為6的結(jié)點插入其前,如圖8-10所示。圖8-10結(jié)點插在表頭

(2)結(jié)點插在表中間。在上面鏈表的基礎上插入數(shù)值為9的結(jié)點,如圖8-11所示。

(3)結(jié)點插在表尾。在上面鏈表的基礎上在表尾插入數(shù)值為16的結(jié)點,如圖8-12所示。插在表尾,意味著在while循環(huán)中以p1=NULL為條件而退出循環(huán)。圖8-11結(jié)點插在表中間圖8-12結(jié)點插在表尾

4.刪除結(jié)點從一個鏈表中刪除結(jié)點也應考慮以下幾種情況:

(1)刪除表頭結(jié)點。

(2)刪除表中或表尾結(jié)點。

(3)找不到要刪的結(jié)點。完成該功能的函數(shù)中使用了三個工作指針:p1,指向當前考查結(jié)點;p2,指向當前結(jié)點的前一結(jié)點;temp,指向被刪結(jié)點。函數(shù)如下:

Node*delete(Node*h,intvalue){Node*p1,*p2,*temp;if(value==h->data) /*刪除表頭結(jié)點*/{temp=h;h=h->next; /*解除表頭與鏈表的連接*/free(temp); /*釋放該結(jié)點的內(nèi)存*/}else{p2=h;p1=h->next;while(p1!=NULL&&p1->data!=value){p2=p1; /*移到…*/p1=p1->next; /*…下一個結(jié)點*/}if(p1!=NULL) /*即p1->data==value*/{temp=p1;p2->next=p1->next;free(temp);

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論