從問題到程序:CC++程序設(shè)計(jì)基礎(chǔ) 課件 PtoP-8-結(jié)構(gòu)體_第1頁
從問題到程序:CC++程序設(shè)計(jì)基礎(chǔ) 課件 PtoP-8-結(jié)構(gòu)體_第2頁
從問題到程序:CC++程序設(shè)計(jì)基礎(chǔ) 課件 PtoP-8-結(jié)構(gòu)體_第3頁
從問題到程序:CC++程序設(shè)計(jì)基礎(chǔ) 課件 PtoP-8-結(jié)構(gòu)體_第4頁
從問題到程序:CC++程序設(shè)計(jì)基礎(chǔ) 課件 PtoP-8-結(jié)構(gòu)體_第5頁
已閱讀5頁,還剩108頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡介

第8章

結(jié)構(gòu)體和其它數(shù)據(jù)機(jī)制高級語言程序設(shè)計(jì)2本章概述介紹C/C++語言的其他數(shù)據(jù)描述機(jī)制,主要是類型定義和結(jié)構(gòu)體(struct)。各種數(shù)據(jù)機(jī)制的概念、意義和用途。在寫處理復(fù)雜數(shù)據(jù)的程序,在定義復(fù)雜數(shù)據(jù)類型和結(jié)構(gòu)時(shí),這些機(jī)制應(yīng)用廣泛。“數(shù)據(jù)結(jié)構(gòu)”課程中將大量使用這些機(jī)制。這里主要介紹概念,給出一些程序?qū)嵗?。并介紹一些相關(guān)的概念和技術(shù)。3第8章結(jié)構(gòu)體和其它數(shù)據(jù)機(jī)制8.1定義類型

8.1.1簡單類型定義

8.1.2定義數(shù)組類型 8.1.2定義函數(shù)指針類型8.2結(jié)構(gòu)體(struct)8.3結(jié)構(gòu)體編程實(shí)例8.4鏈接結(jié)構(gòu)體(自引用結(jié)構(gòu)體)48.1定義類型語言為各種基本類型提供了類型名,可用于定義/說明變量,描述函數(shù)參數(shù)與返回值,類型強(qiáng)制等。數(shù)組、指針等等可能使說明變得很復(fù)雜,使用不便。也不容易保證多個(gè)類型描述的一致性。如果能把復(fù)雜類型描述看作類型(用戶定義類型)加以命名,可帶來很大方便,特別是在實(shí)現(xiàn)復(fù)雜程序/軟件系統(tǒng)時(shí)。定義類型是重要語言機(jī)制,定義好的類型最好能像內(nèi)部類型一樣使用。C語言類型定義機(jī)制較弱,主要作用是簡化描述,增強(qiáng)程序可讀性。C++功能更強(qiáng)。4558.1.1簡單類型定義類型定義用關(guān)鍵字

typedef:

typedef原有類型名新類型名;C/C++并不認(rèn)為使用typedef定義的類型是新類型,而認(rèn)為它們只是原有類型的新名字(別名)。例1:typedeflongdouble

Ldouble;定義后的Ldouble可以像基本類型名一樣用:Ldoublex,y,*p;Ldoublefun1(doublex,Ldoubley);這種類型定義可以簡化程序書寫,有一定實(shí)際價(jià)值。注意區(qū)分宏定義“#define”

6定義新類型名可以提高程序的可讀性,使程序更清晰。例2:程序的返回值為整數(shù)時(shí),它是表示算術(shù)計(jì)算結(jié)果,還是表示函數(shù)的工作狀態(tài)?int

func(intm,doublex);定義別名“Status”,用該別名說明函數(shù)的返回值類型:

typedefint

Status;

Status

func(intm,doublex);定義指針類型為新類型,可以提高程序的可讀性,減少出錯(cuò)可能性。例3: char*pa,pb; //pb是什么類型?把字符指針類型定義為新類型,就可以減少出錯(cuò)可能性:

typedefchar*

pchar;

pcharpa,pb;78.1.2定義數(shù)組類型例如,定義一種具有4個(gè)元素的雙精度數(shù)組類型:

typedefdoubleVect4[4];此后可以寫:

Vect4v1,v2;//定義兩個(gè)數(shù)組變量

Vect4*pvect;//定義指針變量

doubledet(Vect4v);//用于說明函數(shù)參數(shù)78.1.3定義函數(shù)指針類型函數(shù)指針參數(shù)名被有關(guān)描述的各種成分重重包裹,很不顯眼,影響閱讀和理解:doublechordroot(double(*pf)(double),doublex1,doublex2);用typedef定義函數(shù)指針類型:typedefdouble(*

MathFun)(double);可用于描述這種類型的函數(shù)指針參數(shù)或定義函數(shù)指針變量:doublechordroot(MathFunpf,doublex1,doublex2);89第8章結(jié)構(gòu)體和其它數(shù)據(jù)機(jī)制8.1定義類型8.2結(jié)構(gòu)體(struct)8.2.1結(jié)構(gòu)體類型定義8.2.2結(jié)構(gòu)體變量定義和初始化8.2.3結(jié)構(gòu)體變量的使用8.2.4結(jié)構(gòu)體與函數(shù)8.2.5結(jié)構(gòu)體、數(shù)組與指針8.3結(jié)構(gòu)體編程實(shí)例8.4鏈接結(jié)構(gòu)體(自引用結(jié)構(gòu)體)108.2結(jié)構(gòu)體(struct)被處理的數(shù)據(jù)常常形成一些邏輯整體,具有緊密的內(nèi)在聯(lián)系。各成分的性質(zhì)類似(同類型)時(shí)可以用數(shù)組。數(shù)據(jù)體成分類型不同的情況很普遍。如居民身份證,成分有:姓名、性別、出生日期、住址……。這組信息共同描述了一個(gè)居民。無法用數(shù)組表示。許多語言提供了將多個(gè)相同或不同類型的數(shù)據(jù)組合起來的機(jī)制,常稱記錄(record),C/C++稱為結(jié)構(gòu)體(structure)。結(jié)構(gòu)體是復(fù)合數(shù)據(jù)對象,其中的數(shù)據(jù)項(xiàng)稱為結(jié)構(gòu)體的成員或成分。成員給定名字,通過成員名訪問。118.2.1結(jié)構(gòu)體類型要定義一種結(jié)構(gòu)體類型,就需要描述它的各個(gè)成員的情況,包括每個(gè)成員的類型及名字。結(jié)構(gòu)體類型描述由struct引導(dǎo),基本形式:

struct結(jié)構(gòu)體標(biāo)志

{成員說明序列

};

形式與變量定義相同結(jié)構(gòu)體里可以有任意多個(gè)成員,成員可以是任何可用類型。structDot{

doublex,y;};struct

Dot2{

doublecrd[2];};例如,平面上的一個(gè)點(diǎn)的結(jié)構(gòu)體:結(jié)構(gòu)體標(biāo)志結(jié)構(gòu)體標(biāo)志結(jié)構(gòu)體成員結(jié)構(gòu)體成員12在C語言中,以上語句定義了一種結(jié)構(gòu)體類型,在后續(xù)使用時(shí)要把“struct”關(guān)鍵詞和結(jié)構(gòu)體標(biāo)志寫在一起來使用這種結(jié)構(gòu)體類型。例如:structDot結(jié)構(gòu)體中的成員也可以是已經(jīng)定義好的結(jié)構(gòu)體類型。已定義的結(jié)構(gòu)體類型可以用于定義其它結(jié)構(gòu)體類型。structCircle{

structDot

center;doubleradius;};例:13為了使語句更簡潔,通常用typedef把結(jié)構(gòu)體類型重新命名為一個(gè)新的類型名和相應(yīng)的指針類型名:

typedefstructDot

Dot; typedefstructDot*

PtrDot;可以把結(jié)構(gòu)體類型的定義和類型命名合寫在一起:typedefstructCircle{ Dotcenter; doubleradius;}Circle,*PtrCircle;typedefstructDot{ doublex,y;}Dot,*PtrDot;這種寫法很常見!14注意:(1)在定義結(jié)構(gòu)體類型時(shí),一個(gè)結(jié)構(gòu)體類型中的成員名字不能重名,而不同的結(jié)構(gòu)體類型中則完全可以包含名稱相同的成員,彼此無關(guān)。typedefstructCoord3d{doublex,y,z;}Coord,*PtrCoord;(2)在定義結(jié)構(gòu)體類型時(shí),結(jié)構(gòu)體的成員不能是正在描述的這個(gè)結(jié)構(gòu)體本身。structInvalid{ intn;

structInvalidiv; //錯(cuò)誤};附錄4

命名規(guī)范本書中使用的命名規(guī)范如下:1、常量(常變量、枚舉常量和宏)使用全部大寫的字母;2、普通變量和函數(shù)參數(shù)通常用全小寫字母。而且i、j、k、m、n等字母或以它們開頭的變量名只用于說明整型變量(不用于說明實(shí)型變量),而x、y和z只用于說明實(shí)型變量。3、函數(shù)名通常用全小寫字母。當(dāng)名稱為“動(dòng)詞+名詞”的形式時(shí)使用小駝峰式命名(動(dòng)詞為小寫,名詞為首字母大寫)。4、結(jié)構(gòu)體標(biāo)志和用typedef定義的類型名稱用大駝峰式命名(每個(gè)單詞的首字母大寫)。15168.2.2結(jié)構(gòu)體變量定義和初始化在程序里使用結(jié)構(gòu)體,那么就需要定義結(jié)構(gòu)體變量(以結(jié)構(gòu)體為類型的變量)??捎谩皊truct結(jié)構(gòu)體標(biāo)志”:structDotdot1,dot2;或用typedef定義的類型名:Dotdot3,dot4;Circlecir1,cir2;也可以定義相應(yīng)的指針變量(可初始化):structDot*pdot1;PtrDotpdot2=&dot2;17所定義的結(jié)構(gòu)體變量在內(nèi)存中占用多大存儲(chǔ)空間?在計(jì)算機(jī)中存儲(chǔ)一個(gè)結(jié)構(gòu)體數(shù)據(jù)對象(例如結(jié)構(gòu)體變量)就需要存儲(chǔ)其中的各個(gè)成員。編譯系統(tǒng)將為每個(gè)結(jié)構(gòu)體變量分配一塊足夠大的存儲(chǔ)區(qū),把它的各個(gè)成員順序存于其中。Circle結(jié)構(gòu)體變量:xyradiusDot結(jié)構(gòu)體成員center實(shí)際大小需要使用sizeof運(yùn)算符計(jì)算出來才準(zhǔn)確。18與簡單類型變量和數(shù)組一樣,結(jié)構(gòu)體變量也可以在定義時(shí)直接初始化。形式與數(shù)組一樣:Dotdot1={2.34,3.28},dot2;Circlecirc1={{3.5,2.07},1.25},circ2={12.35,10.6,2.56};初始化描述中的各個(gè)值將順序地提供給結(jié)構(gòu)體變量的各個(gè)基本成員,初值表達(dá)式必須是可靜態(tài)求值的表達(dá)式。嵌套結(jié)構(gòu)可以加括號。項(xiàng)數(shù)不得多于結(jié)構(gòu)體變量所需,不夠時(shí)剩下的成分自動(dòng)初始化為0。未提供初始值時(shí),外部和靜態(tài)局部結(jié)構(gòu)體變量的成員初始化為0,自動(dòng)變量不自動(dòng)初始化。初值表達(dá)式只能用于變量定義,不能出現(xiàn)在語句里。結(jié)構(gòu)體類型和結(jié)構(gòu)體變量的定義有多種寫法。上面介紹的是最常用和最簡潔的寫法。下面是其它寫法。19在定義結(jié)構(gòu)體類型的同時(shí)定義結(jié)構(gòu)體變量:structDot{doublex,y;}dot1,dot2;//變量dot1,dot2;此時(shí)不能同時(shí)用typedef定義新類型名??梢詥为?dú)另寫:typedefstructDotDot;定義結(jié)構(gòu)體類型時(shí)省略結(jié)構(gòu)體標(biāo)志。這會(huì)導(dǎo)致無法使用“struct結(jié)構(gòu)體標(biāo)志”來說明結(jié)構(gòu)體類型。所以此時(shí)必須用typedef定義新類型名,或同時(shí)定義結(jié)構(gòu)體變量。typedefstruct{doublex,y;}Dot;struct{doublex,y;}dot1,dot2;額外說明208.2.3結(jié)構(gòu)體變量的使用對結(jié)構(gòu)體變量的操作:結(jié)構(gòu)體成員訪問和整體賦值訪問結(jié)構(gòu)體成員的操作用圓點(diǎn)運(yùn)算符"."

描述。具有最高的優(yōu)先級,采用自左向右的結(jié)合方式。

dot1.x=dot1.y=0.0;dot2.x=dot1.x+2.4;dot2.y=dot1.y+4.8;circ1.radius=0.9;當(dāng)某個(gè)結(jié)構(gòu)體的成員是另一個(gè)結(jié)構(gòu)體時(shí),需要使用多級圓點(diǎn)運(yùn)算符。

circ1.center.x=2.0;circ1.center.y=dot1.y+3.5;circ2.center.x+=2.8; circ2.center.y+=0.24;相當(dāng)于訪問一個(gè)具有相應(yīng)類型的變量,操作由類型決定。程序里也可以用&取得結(jié)構(gòu)體變量或其成員的地址。21結(jié)構(gòu)體變量可以用同樣類型的結(jié)構(gòu)體值做整體賦值。效果:結(jié)構(gòu)體中各個(gè)成員的分別賦值。

circ2=circ1; dot2=dot1;circ1.center=dot1;變量circ2、dot2各成員的值將分別與circ1、dot1對應(yīng)成員的值完全一樣。不能對結(jié)構(gòu)體做相等與不等比較,也不能做其它運(yùn)算。22對于結(jié)構(gòu)體指針變量,在引用其所指結(jié)構(gòu)體變量的成員時(shí),可以有兩種方法。(1)先用*

作對所指結(jié)構(gòu)體變量進(jìn)行間接訪問,然后再用圓點(diǎn)運(yùn)算符引用其成員。

structDot*pdot=&dot1;//定義指針變量并初始化

(*pdot).x

=0;

(*pdot).y

=0;由于圓點(diǎn)運(yùn)算符的優(yōu)先級高,此處必須寫括號。不寫括號的描述*pdot.x和*pdot.y是錯(cuò)誤的,實(shí)際上表示的是*(pdot.x)和*(pdot.y)。23(2)為了方便從指針出發(fā)去訪問結(jié)構(gòu)體成員,C/C++語言為這種操作專門提供了運(yùn)算符號“->”(“箭頭運(yùn)算符”)。

pdot->x相當(dāng)于(*pdot).x,

pdot->y相當(dāng)于(*pdot).y。于是可以寫:

pdot->x=0;pdot->y=0;運(yùn)算符->

也具有最高優(yōu)先級(與圓點(diǎn)運(yùn)算符、函數(shù)調(diào)用()及數(shù)組元素訪問[]

一樣),它也遵循從左向右的結(jié)合方式。附錄1

C和C++語言運(yùn)算符表24運(yùn)算符解釋結(jié)合方式()[]->.括號(函數(shù)等),數(shù)組,兩種結(jié)構(gòu)體成員訪問由左向右!~++

--+-*

&(類型)sizeof邏輯否定,按位否定,增量,減量,正負(fù)號,間接訪問,取地址,類型轉(zhuǎn)換,求占用內(nèi)存大小由右向左*/%乘,除,取模由左向右+-加,減由左向右<<>>左移,右移由左向右<<=>=>小于,小于等于,大于等于,大于由左向右==!=等于,不等于由左向右&按位與由左向右^按位異或由左向右|按位或由左向右&&邏輯與由左向右||邏輯或由左向右?:條件運(yùn)算由右向左=+=-=*=/=&=^=|=<<=>>=各種賦值由右向左,逗號(順序)由左向右全書至此已介紹了所有運(yùn)算符,必要時(shí)可翻閱附錄125【例8-1】請用戶輸入平面上的一個(gè)點(diǎn)的坐標(biāo),再輸入一個(gè)圓的圓心和半徑,然后判斷該點(diǎn)是否在該圓的內(nèi)部(即點(diǎn)與圓心之間的距離是否小于圓的半徑)。在程序頭部先定義坐標(biāo)點(diǎn)結(jié)構(gòu)體類型和圓結(jié)構(gòu)體類型:#include<iostream>#include<cmath>usingnamespacestd;typedefstructDot{ doublex,y;}Dot;//點(diǎn)結(jié)構(gòu)體類型typedefstructCircle{ Dotcenter; doubleradius;}Circle;//圓結(jié)構(gòu)體類型26intmain(){

Dotdot1;Circlecirc1; doubledist; cout<<"InputaDot(xy):";

cin>>dot1.x>>dot1.y;//輸入 cout<<"InputaCircle(xyr):"; cin>>circ1.center.x>>circ1.center.y>>circ1.radius;//輸入 dist=sqrt((dot1.x-circ1.center.x)*(dot1.x-circ1.center.x) +(dot1.y-circ1.center.y)*(dot1.y-circ1.center.y));//計(jì)算 cout<<"distance:"<<dist<<endl; if(dist<circ1.radius)cout<<"dot1isinsidecirc1.\n"; elsecout<<"dot1isNOTinsidecirc1.\n"; return0;}續(xù)然后在main函數(shù)中定義相應(yīng)的變量,再進(jìn)行輸入和計(jì)算操作。(x,y)((x,y),r)27第8章結(jié)構(gòu)體和其它數(shù)據(jù)機(jī)制8.1定義類型8.2結(jié)構(gòu)體(struct)8.2.1結(jié)構(gòu)體類型定義8.2.2結(jié)構(gòu)體變量定義和初始化8.2.3結(jié)構(gòu)體變量的使用8.2.4結(jié)構(gòu)體與函數(shù)8.2.5結(jié)構(gòu)體、數(shù)組與指針8.3結(jié)構(gòu)體編程實(shí)例8.4鏈接結(jié)構(gòu)體(自引用結(jié)構(gòu)體)288.2.4結(jié)構(gòu)體與函數(shù)結(jié)構(gòu)體類型既可以作為函數(shù)返回值類型,也可以作為函數(shù)的參數(shù)類型。在書寫上同樣既可以用“struct結(jié)構(gòu)體標(biāo)志”這種形式,也可以用typedef定義的類型名。把結(jié)構(gòu)體類型作為函數(shù)返回值類型時(shí),只需要在函數(shù)聲明或函數(shù)定義的返回值類型處寫結(jié)構(gòu)體類型。例如:

structDotmkDot(doublex,doubley);

CirclemkCircle(doublex,doubley,doubler);29使用函數(shù)處理存儲(chǔ)在結(jié)構(gòu)體中的數(shù)據(jù)時(shí),既可以分散使用結(jié)構(gòu)體成員,也可以整體使用結(jié)構(gòu)體:(1)個(gè)別地將結(jié)構(gòu)體成員的值傳遞給函數(shù)處理(可以用值參數(shù)、引用參數(shù)或指針參數(shù)等方式)。(2)當(dāng)結(jié)構(gòu)體參數(shù)的成員值不需要改變時(shí),可以將整個(gè)結(jié)構(gòu)體作為參數(shù)值傳遞給函數(shù)

結(jié)構(gòu)體值參數(shù)(3)當(dāng)結(jié)構(gòu)體參數(shù)需要改變時(shí),可以用C++中的引用方式傳遞結(jié)構(gòu)體參數(shù)

結(jié)構(gòu)體引用參數(shù)(4)將結(jié)構(gòu)體的地址傳給函數(shù),也就是說傳遞指向結(jié)構(gòu)體的指針值。這稱為結(jié)構(gòu)體指針參數(shù)。把結(jié)構(gòu)體作為整體來看待和處理,三種參數(shù)機(jī)制的作用方式和效果不同。30【例8-2】請用戶輸入平面上的一個(gè)點(diǎn)的坐標(biāo),再輸入一個(gè)圓的圓心和半徑,然后判斷該點(diǎn)是否在該圓的內(nèi)部(即點(diǎn)與圓心之間的距離是否小于圓的半徑)。要求寫一系列的函數(shù)實(shí)現(xiàn)題目中的功能。這個(gè)程序的功能有三部分:1.給一個(gè)Dot類型的變量賦值,2.給一個(gè)Circle類型的變量賦值,3.使用一個(gè)Dot類型變量的成員和一個(gè)Circle類型變量的成員進(jìn)行計(jì)算。把三個(gè)功能分別寫為三個(gè)函數(shù),然后在主函數(shù)中進(jìn)行調(diào)用。(x,y)((x,y),r)31前兩個(gè)功能中,是提供一些double參數(shù)值給結(jié)構(gòu)體變量的成員賦值,函數(shù)的返回值類型為結(jié)構(gòu)體類型:structDotmkDot(doublex,doubley){structDottemp;temp.x=x;temp.y=y;returntemp;}CirclemkCircle(doublex,doubley,doubler){Circletemp;temp.center.x=x;temp.center.y=y;temp.radius=r;returntemp;}(x,y)((x,y),r)32對于第三個(gè)功能“計(jì)算平面上一個(gè)點(diǎn)與一個(gè)圓的距離”,根據(jù)不同的參數(shù)形式,可以寫出不同形式的函數(shù)。(1)把結(jié)構(gòu)體的成員值作為參數(shù)傳遞給函數(shù):doubledist1(doublex1,doubley1,doublex2,doubley2){//值參數(shù)

doubledist;dist=sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));returndist;}調(diào)用語句:dist=

dist1(dot1.x,dot1.y,circ1.center.x,circ1.center.y);把結(jié)構(gòu)體作為一個(gè)整體作為參數(shù)傳遞給函數(shù),有三種寫法:33doubledist2(Dotdot,Circlecirc){//結(jié)構(gòu)體值參數(shù)

doubledist;dist=sqrt((dot.x-circ.center.x)*(dot.x-circ.center.x)+(dot.y-circ.center.y)*(dot.y-circ.center.y));returndist;}doubledist3(Dot&dot,Circle&circ){//結(jié)構(gòu)體引用參數(shù)

returnsqrt((dot.x-circ.center.x)*(dot.x-circ.center.x)+(dot.y-circ.center.y)*(dot.y-circ.center.y));}doubledist4(Dot*dot,Circle*circ){//結(jié)構(gòu)體指針參數(shù)

returnsqrt((dot->x-circ->center.x)*(dot->x-circ->center.x)+(dot->y-circ->center.y)*(dot->y-circ->center.y));//注意上式中->與.的用法}34主函數(shù):intmain(){Dotdot1;Circlecirc1;doublex,y,r,dist;

cout<<"InputaDot(xy):";cin>>x>>y;dot1=mkDot(x,y);//!!!

cout<<"Inputtheacircle(xyr):";cin>>x>>y>>r;circ1=mkCircle(x,y,r);//!!!

dist=dist1(dot1.x,dot1.y,circ1.center.x,circ1.center.y);//成員參數(shù)

cout<<"distance:"<<dist<<endl;35dist=dist2(dot1,circ1);//結(jié)構(gòu)體值參數(shù)

cout<<"distance:"<<dist<<endl;dist=dist3(dot1,circ1);//結(jié)構(gòu)體引用參數(shù)

cout<<"distance:"<<dist<<endl;dist=dist4(&dot1,&circ1);//結(jié)構(gòu)體指針參數(shù)

cout<<"distance:"<<dist<<endl;

if(dist<circ1.radius)cout<<"dot1isinsideofthecirc1."<<endl;elsecout<<"dot1isNOTinsideofcirc1."<<endl;return0;}36doubledist1(doublex1,doubley1,doublex2,doubley2);使用結(jié)構(gòu)體成員作為參數(shù)時(shí),由于結(jié)構(gòu)體的每個(gè)成員都要寫成一個(gè)參數(shù),參數(shù)列表中的內(nèi)容比較多。doubledist2(Dotdot,Circlecirc);//結(jié)構(gòu)體值參數(shù)使用結(jié)構(gòu)體值參數(shù)的方法需要在運(yùn)行函數(shù)時(shí)新建同類型的結(jié)構(gòu)體變量、并進(jìn)行變量值復(fù)制。在處理大型的結(jié)構(gòu)體變量時(shí),這種方法效率較低。doubledist3(Dot&dot,Circle&circ);//結(jié)構(gòu)體引用參數(shù)doubledist4(Dot*dot,Circle*circ);//結(jié)構(gòu)體指針參數(shù)采用引用或指針的一個(gè)優(yōu)點(diǎn)是可以避免復(fù)制整個(gè)結(jié)構(gòu)體。建議在使用結(jié)構(gòu)體整體作為函數(shù)參數(shù)時(shí),采用引用形式或指針形式為好。

多種方式的比較:37*擴(kuò)展說明:C中的結(jié)構(gòu)體只包含成員變量;C++中的結(jié)構(gòu)體和“類(Class)”更復(fù)雜一些,可以包含成員函數(shù)。成員變量和成員函數(shù)都是用圓點(diǎn)運(yùn)算符.來調(diào)用。cin.get(),cin.clear(),cin.sync().infile.open(),infile.close()38第8章結(jié)構(gòu)體和其它數(shù)據(jù)機(jī)制8.1定義類型8.2結(jié)構(gòu)體(struct)8.2.1結(jié)構(gòu)體類型定義8.2.2結(jié)構(gòu)體變量定義和初始化8.2.3結(jié)構(gòu)體變量的使用8.2.4結(jié)構(gòu)體與函數(shù)8.2.5結(jié)構(gòu)體、數(shù)組與指針8.3結(jié)構(gòu)體編程實(shí)例8.4鏈接結(jié)構(gòu)體(自引用結(jié)構(gòu)體)398.2.5結(jié)構(gòu)體、數(shù)組與指針前文都是用

點(diǎn)、圓

這樣簡單的結(jié)構(gòu)體類型進(jìn)行舉例說明。實(shí)際應(yīng)用中,結(jié)構(gòu)體類型的組成結(jié)構(gòu)可能比較復(fù)雜。結(jié)構(gòu)體里可以包含數(shù)組成員。例如定義表示學(xué)生信息的結(jié)構(gòu)體類型中,姓名、院系和專業(yè)都是字符數(shù)組(末尾至少要允許存放一個(gè)空字符):typedefstructStudent{intid;//學(xué)號charname[21];//姓名(可存儲(chǔ)至多10個(gè)漢字)chargender;//性別(用字符M或F表示)chardepartment[21];//院系

charmajor[21];//專業(yè)}Student,*PtrStudent;*附加討論:上面定義的學(xué)生信息結(jié)構(gòu)體類型中,學(xué)號

是用

int類型表示,總是可以這樣做嗎?答:這取決于給定的編號規(guī)則。如果學(xué)號的編號規(guī)則滿足以下條件:(1)

由0~9數(shù)字組成(不含其它字符)(2)長度小于10位(INT_MAX為2147483647)(3)首位數(shù)字不是0那么可以設(shè)定為使用int類型。例如:編號規(guī)則為

年份(4位)+院系(2位)+順序號(4位),用int類型(或unsignedint)是可以的。如果編號規(guī)則不滿足以上三個(gè)條件,就要設(shè)定為用

字符數(shù)組

來表示。40intid;//學(xué)號例1:中國的身份證號碼由

18

位數(shù)字和字母組成:前

6

位為發(fā)證地區(qū)代碼,中間

8

位為出生日期碼,后

4

位為順序碼和校驗(yàn)碼(尾數(shù)為0~9或

X)。定義表示身份證信息的結(jié)構(gòu)體類型時(shí),表示身份證號的成員應(yīng)該用字符數(shù)組表示,長度至少為

19

位(末尾能存放一個(gè)空字符表示結(jié)束),更長一點(diǎn)可以增強(qiáng)容錯(cuò)性。typedefstructIdCard{

charid[20];//身份證號

charname[21];//姓名(最多10個(gè)漢字)charsex;//在內(nèi)部用M或F表示//charsex[3];//用漢字“男”和“女”表示charnationality[11];//民族(最多5個(gè)漢字)

constchar*address;//地址(字符常量指針)}IdCard,*PtrIdCard;41如果編號規(guī)則不滿足以上三個(gè)條件,就要設(shè)定為用

字符數(shù)組

來表示。例2:正式出版的書籍都有唯一的國際標(biāo)準(zhǔn)書號(ISBN),在當(dāng)代,ISBN是由

13位數(shù)字構(gòu)成。因此,定義表示書籍信息的結(jié)構(gòu)體類型時(shí),表示ISBN的成員應(yīng)該用

字符數(shù)組表示,長度至少為

14位。typedefstructBook{

charisbn[15];

//書號chartitle[50]; //書名charauthor[32]; //作者

charpress[50]; //出版社intyear; //出版年份

floatprice; //定價(jià)}Book,*PtrBook;42如果編號規(guī)則不滿足以上三個(gè)條件,就要設(shè)定為用

字符數(shù)組

來表示。另一方面,也可以定義以結(jié)構(gòu)體作為元素的數(shù)組。定義方法與其它類型的數(shù)組相似:元素類型名

數(shù)組名[數(shù)組長度];【例8-3】在二維平面坐標(biāo)上有100個(gè)x和y值都在[0,100]范圍內(nèi)的隨機(jī)點(diǎn),把它們的坐標(biāo)依次全部輸出到屏幕,并求它們的幾何中心。分別使用兩種方法處理:(1)采用兩個(gè)數(shù)組分別保存x值和y值;(2)使用平面點(diǎn)結(jié)構(gòu)體數(shù)組。4344intmain(){constintNUM=100;

doublex[NUM],y[NUM],sumx=0,sumy=0;cout<<"100randompointsonsurface.UsingXYarrays.\n\n"srand(time(0));for(inti=0;i<NUM;i++){

x[i]=1.0*rand()/RAND_MAX*100;

y[i]=1.0*rand()/RAND_MAX*100;cout<<"i="<<i<<"\tx="<<x[i]<<"\ty="<<y[i]<<endl;}for(inti=0;i<NUM;i++){sumx+=x[i];sumy+=y[i];}cout<<"averagex="<<sumx/NUM<<"averagey="<<sumy/NUM;return0;}方法(1):定義兩個(gè)長度為100的數(shù)組,分別保存x值和y值,然后再分別求平均值:45方法(2):使用表示二維平面點(diǎn)的結(jié)構(gòu)體數(shù)組。設(shè)想出程序的主體內(nèi)容和基本流程如下:定義結(jié)構(gòu)體類型;定義結(jié)構(gòu)體數(shù)組;使用隨機(jī)數(shù)函數(shù)設(shè)定各點(diǎn)的坐標(biāo);計(jì)算數(shù)組中的二維坐標(biāo)平均值(幾何中心);輸出結(jié)果;46typedefstructDot{doublex,y;}Dot;intmain(){constintNUM=100;Dotpt[NUM],cent={0,0};srand(time(0));for(inti=0;i<NUM;i++){

pt[i].x=1.0*rand()/RAND_MAX*100;

pt[i].y=1.0*rand()/RAND_MAX*100;cout<<i<<":("<<pt[i].x<<","<<pt[i].y<<")"<<endl;}定義結(jié)構(gòu)體類型定義結(jié)構(gòu)體數(shù)組使用隨機(jī)數(shù)函數(shù)設(shè)定各點(diǎn)的坐標(biāo)47for(inti=0;i<NUM;i++){

cent.x+=pt[i].x;

cent.y+=pt[i].y;}cent.x/=NUM;cent.y/=NUM;cout<<"center:("<<cent.x<<","<<cent.y<<")"<<endl;return0;}計(jì)算數(shù)組中的二維坐標(biāo)平均值(幾何中心)輸出結(jié)果【例+】在一個(gè)簡單的職工信息管理系統(tǒng)中,每個(gè)職工具有姓名(最長5個(gè)漢字)、性別(用字符M和F表示)、出生年份和部門(最長10個(gè)漢字)等四項(xiàng)信息。(1)請?jiān)O(shè)計(jì)表示職工信息的結(jié)構(gòu)體類型WorkerInfo。(2)在程序中定義長度為100

的該結(jié)構(gòu)體類型的數(shù)組,并初始化為存放5個(gè)自行編造的職工示例數(shù)據(jù)。張三強(qiáng)M1998管理科李玉沛F2000設(shè)計(jì)局王子含M2001生產(chǎn)車間李倍慶F1999銷售科梅俊才M2002財(cái)務(wù)室(用示例數(shù)據(jù)初始化是為了降低題目難度,不涉及文件讀寫)

(3)實(shí)現(xiàn)姓名模糊查找:輸入文字(1-3個(gè)字),找出職工姓名中包含這串文字的職工并輸出完整信息,并統(tǒng)計(jì)人數(shù)。48在程序頭部定義表示職工信息的結(jié)構(gòu)體類型:#include<iostream>#include<string.h>//字符函數(shù)頭文件usingnamespacestd;typedefstructWorkerInfo{charname[11];//姓名(最長5個(gè)漢字)

charsex; //性別(用字符M和F表示)

intyear;//出生年份chardept[21];//部門(最長10個(gè)漢字)}WorkerInfo,*PtrWorkerInfo;49然后寫出main函數(shù)實(shí)現(xiàn)其它功能:intmain(){

WorkerInfoworker[100]={//定義結(jié)構(gòu)體數(shù)組并初始化 {"李三強(qiáng)",'M',1998,"管理科"}, {"張玉沛",'F',2000,"設(shè)計(jì)局"}, {"王子含",'M',2001,"生產(chǎn)車間"}, {"李倍慶",'F',1999,"銷售科"}, {"梅俊才",'M',2002,"財(cái)務(wù)室"} }; intn=5;//當(dāng)前職工人數(shù) charname[11]; cout<<"請輸入待查找的姓名:"; cin>>name;50 intcnt=0;//找到的結(jié)果數(shù)目 cout<<"查找結(jié)果:"<<endl; for(intk=0;k<n;k++){ if(strstr(worker[k].name,name)){//用strstr比較 cout<<worker[k].name<<"\t"<<worker[k].sex<<"\t" <<worker[k].year<<"\t"<<worker[k].dept<<endl; cnt++; } } cout<<"結(jié)果數(shù):"<<cnt<<endl; return0;}51char*strstr(constchars1[],constchars2[])返回子字符串

s2

在目標(biāo)字符串

s1

中第一次出現(xiàn)的位置,如果沒有出現(xiàn)就返回

NULL。注意:函數(shù)strcmp是按字典序?qū)蓚€(gè)字符串進(jìn)行比較(相等時(shí)返回值0),不適用于模糊查找。52【例8-4】假設(shè)有一個(gè)名為“####-mxyz.txt”的數(shù)據(jù)文件,其中存儲(chǔ)了一個(gè)大分子中各個(gè)原子的信息,數(shù)據(jù)在文件中分為四列,分別表示原子的質(zhì)量和XYZ坐標(biāo),各列之間用制表符分隔,首行是文字注釋,隨后的每一行分別表示一個(gè)原子的信息,其中可能有空行。如下所示:mass x y z1 58.839 78.090 61.91512 58.510 77.806 61.0061 59.119 78.220 60.24512 58.674 76.279 60.85216 58.167 75.595 61.73814 59.467 75.715 59.849...整個(gè)文件的行數(shù)(原子個(gè)數(shù))事先未知。請編寫程序讀取該文件中的數(shù)據(jù)到一個(gè)原子結(jié)構(gòu)體數(shù)組中,然后計(jì)算該分子的質(zhì)量中心。53此題將使用結(jié)構(gòu)體數(shù)組,還復(fù)習(xí):文件讀取動(dòng)態(tài)分配和釋放內(nèi)存設(shè)想出程序的主體內(nèi)容和基本流程如下:定義原子結(jié)構(gòu)體類型;打開文件讀取一次,獲得原子個(gè)數(shù)

n,關(guān)閉文件;定義原子結(jié)構(gòu)體指針,動(dòng)態(tài)分配數(shù)組內(nèi)存;重新打開文件,讀取原子信息,關(guān)閉文件;計(jì)算分子的質(zhì)量中心;釋放動(dòng)態(tài)分配的數(shù)組;#include<iostream>#include<fstream>#include<cstring>usingnamespacestd;typedefstructAtom{doublem,x,y,z;}Atom;intmain(){constintSIZE=100;charstr[SIZE];intn=0;//原子個(gè)數(shù)

charfname[]="####-mxyz.txt";//文件名存儲(chǔ)于字符數(shù)組中ifstreamin;

in.open(fname);//打開文件以供讀取cout<<"讀取數(shù)據(jù)文件:"<<fname<<endl;

54定義結(jié)構(gòu)體類型

in.getline(str,SIZE);

//讀入文件首行注釋(并不使用)while(in.getline(str,SIZE)){//逐行讀入進(jìn)行計(jì)數(shù)if(strlen(str)!=

0)

n++;//cout<<n<<":"<<str<<endl;}//通讀一遍,得到原子總數(shù)

in.close();//關(guān)閉文件cout<<"原子總數(shù):"<<n<<endl;in.open(fname);//重新打開文件再次讀取

in.getline(str,SIZE);//讀入文件首行注釋

Atom*at=newAtom[n];//定義指針變量并申請分配空間//Atomat[n];//定義以變量為長度的數(shù)組(C99)Atomcent={0,0,0,0};//質(zhì)心55for(inti=0;i<n;i++){//讀取原子信息in>>at[i].m>>at[i].x>>at[i].y>>at[i].z;//數(shù)組寫法//in>>(at+i)->m>>(at+i)->x>>(at+i)->y>>(at+i)->z;

//指針寫法//cout<<i<<":"<<at[i].m<<""<<at[i].x<<""http://<<at[i].y<<""<<at[i].z<<endl;}in.close();//關(guān)閉文件

for(inti=0;i<n;i++){//計(jì)算質(zhì)心:先累加cent.m+=at[i].m;//質(zhì)量累加cent.x+=at[i].m*at[i].x;cent.y+=at[i].m*at[i].y;cent.z+=at[i].m*at[i].z;}56//計(jì)算質(zhì)心:除以總質(zhì)量cent.x/=cent.m;cent.y/=cent.m;cent.z/=cent.m;

cout<<"質(zhì)心坐標(biāo):("<<cent.x<<","<<cent.y<<","<<cent.z<<")\n";

delete[]at;

//釋放動(dòng)態(tài)分配的數(shù)組存儲(chǔ)空間

return0;}57小結(jié)(8.1~8.2)用typedef作類型定義typedef原類型名

新類型名;定義結(jié)構(gòu)體類型并同時(shí)定義新類型typedefstruct結(jié)構(gòu)體標(biāo)志{

成員列表;}結(jié)構(gòu)體類型名;*結(jié)構(gòu)體指針類型名;定義結(jié)構(gòu)體變量struct結(jié)構(gòu)體標(biāo)志

變量名;結(jié)構(gòu)體類型名

變量名;58訪問結(jié)構(gòu)體成員的方法:結(jié)構(gòu)體變量.成員結(jié)構(gòu)體指針變量->成員名結(jié)構(gòu)體類型中可以包含數(shù)組成員程序中可以定義結(jié)構(gòu)體數(shù)組函數(shù)中可以整體使用結(jié)構(gòu)體作為參數(shù),可以用值參數(shù)、引用參數(shù)或指針參數(shù)。59教學(xué)安排如果課程教學(xué)時(shí)數(shù)緊張,可以在此處結(jié)束教學(xué)。跳轉(zhuǎn)到課件末尾,介紹附錄和進(jìn)一步學(xué)習(xí)的建議。課后作業(yè):ptop-課后作業(yè)-7-8.docx網(wǎng)址:/devcpp/ptop/從“課后作業(yè)”文件夾中下載。60本頁隱藏,不播放61第8章結(jié)構(gòu)體和其它數(shù)據(jù)機(jī)制8.1定義類型8.2結(jié)構(gòu)體(struct)8.3結(jié)構(gòu)體編程實(shí)例8.3.1復(fù)數(shù)的表示和處理

(從底向上開發(fā))8.3.2學(xué)生成績管理系統(tǒng)

(從頂向下開發(fā))8.4鏈接結(jié)構(gòu)體(自引用結(jié)構(gòu)體)8.3結(jié)構(gòu)體編程實(shí)例本節(jié)討論兩個(gè)與結(jié)構(gòu)體等數(shù)據(jù)機(jī)制有關(guān)的編程實(shí)例:8.3.1復(fù)數(shù)的表示和處理

8.3.2學(xué)生成績管理系統(tǒng)

在此過程中介紹一些開發(fā)較大型程序的常用技術(shù),如自底向上開發(fā)、自頂向下開發(fā)、程序參數(shù)存儲(chǔ)等。62數(shù)據(jù)類型基本函數(shù)主程序主程序模塊1模塊2模塊363C/C++語言提供了許多數(shù)值類型可供使用。例如,要編寫處理復(fù)數(shù)數(shù)據(jù)的程序時(shí),可以用C99或C++中的復(fù)數(shù)類型。在此討論如何在程序中自行實(shí)現(xiàn)復(fù)數(shù)的處理,作為編程示例。

簡單想法:用兩個(gè)double數(shù)據(jù)表示一個(gè)復(fù)數(shù)的實(shí)部(real)和虛部(image),考慮定義復(fù)數(shù)加法函數(shù):addcomplex(doubler1,doublei1,doubler2,doublei2);不便返回兩個(gè)double數(shù)據(jù)表示計(jì)算結(jié)果。改為:addcomplex(doubler1,doublei1,doubler2,doublei2,

double*r3,double*i3);參數(shù)較多,使用很麻煩。8.3.1復(fù)數(shù)的表示和處理應(yīng)該看到,一個(gè)復(fù)數(shù)是一個(gè)邏輯上具有整體性的數(shù)據(jù)體,應(yīng)該定義為類型。在這種類型的基礎(chǔ)上定義一批以復(fù)數(shù)類型為操作對象的函數(shù),再去編寫程序的其他部分,程序就會(huì)變得清晰簡單。人們在程序設(shè)計(jì)實(shí)踐中逐步認(rèn)識到,在設(shè)計(jì)實(shí)現(xiàn)一個(gè)較復(fù)雜的程序時(shí),最重要的一個(gè)步驟就是考察程序需求,確定程序里需要的一批數(shù)據(jù)類型,將它們的結(jié)構(gòu)和相關(guān)功能分析清楚,設(shè)計(jì)并予以實(shí)現(xiàn)。然后在這些類型的基礎(chǔ)上實(shí)現(xiàn)整個(gè)程序。這樣做,得到的程序?qū)⒏逦?,其中各個(gè)部分的功能劃分比較明確,容易理解,也更容易修改。這種開發(fā)模式稱為“自底向上”。64【例8-5】考慮實(shí)現(xiàn)一個(gè)復(fù)數(shù)類型。請定義其存儲(chǔ)結(jié)構(gòu),編寫相應(yīng)的算術(shù)函數(shù)和輸入輸出函數(shù)。復(fù)數(shù)有多種數(shù)學(xué)表示方式:平面坐標(biāo),極坐標(biāo)等。選擇平面坐標(biāo),用兩個(gè)實(shí)數(shù)表示一個(gè)復(fù)數(shù),分別表示其實(shí)部和虛部。用什么機(jī)制將這兩部分結(jié)合起來呢?用結(jié)構(gòu)體表示有利于將復(fù)數(shù)作為參數(shù)傳遞和作為結(jié)果返回。因此定義類型如下:typedefstructComplex{doublere,im;//realpart,imagepart}Complex,*PtrComplex;6566下面考慮基于這個(gè)類型的運(yùn)算。由于復(fù)數(shù)對象里的數(shù)據(jù)項(xiàng)很少,可以直接傳遞

Complex

類型的值和結(jié)果,這樣可以避免復(fù)雜的存儲(chǔ)管理問題。函數(shù)名稱中統(tǒng)一使用“Cx”作為“Complex”的縮寫。首先考慮構(gòu)造函數(shù):用兩個(gè)實(shí)數(shù)構(gòu)造一個(gè)復(fù)數(shù):ComplexcreateCx(doublere,doubleim){Complexcx;cx.re=re;cx.im=im;returncx;}67然后考慮復(fù)數(shù)的算術(shù)運(yùn)算(加減乘除)?;镜乃阈g(shù)函數(shù)的原型:ComplexaddCx(Complexx,Complexy);//加ComplexsubCx(Complexx,Complexy);//減ComplextmsCx(Complexx,Complexy);//乘ComplexdivCx(Complexx,Complexy);//除依次寫出:ComplexaddCx(Complexx,Complexy){

//加Complexcx;cx.re=x.re+y.re;cx.im=x.im+y.im;returncx;}ComplexsubCx(Complexx,Complexy){

//減Complexcx;cx.re=x.re-y.re;cx.im=x.im-y.im;returncx;}ComplextmsCx(Complexx,Complexy){

//乘Complexcx;cx.re=x.re*y.re-x.im*y.im;cx.im=x.re*y.im-

x.im*y.re;returncx;}6869ComplexdivCx(Complexx,Complexy);//除復(fù)數(shù)除法函數(shù)有個(gè)新問題:除數(shù)為

0時(shí)該怎么辦?復(fù)數(shù)除法的數(shù)學(xué)定義是(c和d都為0時(shí)出問題):C/C++語言對于內(nèi)部類型除0的規(guī)定是“其行為沒有定義”,也就是說,要求編程者保證不出現(xiàn)這種情況。因此實(shí)現(xiàn)復(fù)數(shù)除法操作時(shí)有兩種選擇:(1)沿用語言要求,要求使用者自行保證不出現(xiàn)除0(如果出現(xiàn)除0,后果自負(fù));(2)檢查除0的情況,提供動(dòng)態(tài)信息并返回某個(gè)特殊值。70采用第二種方式“檢查除0的情況,提供動(dòng)態(tài)信息并返回某個(gè)特殊值”更安全一些。在函數(shù)中檢查是否出現(xiàn)除0的情況。出現(xiàn)除0時(shí)輸出錯(cuò)誤信息并返回值為1的復(fù)數(shù):ComplexdivCx(Complexx,Complexy){Complexcx;doubleden=y.re*y.re+y.im*y.im;if(den==0.0){//如果出現(xiàn)除0cout<<"Complexerror:divid0.\n";//輸出錯(cuò)誤信息cx.re=1;cx.im=0;//返回值為1}else{cx.re=(x.re*y.re+x.im*y.im)/den;cx.im=(x.im*y.re-x.re*y.im)/den;}returncx;}71為了使用方便,還可以定義復(fù)數(shù)的輸出和輸入函數(shù)。輸出函數(shù)向某個(gè)流輸出一個(gè)復(fù)數(shù)。需要事先為復(fù)數(shù)設(shè)想好一種合理的輸出形式。例如(a,bi)。定義如下:voidprtCx(Complexx){cout<<"("<<x.re<<","<<x.im<<"i)";}函數(shù)中僅完成對復(fù)數(shù)的輸出,并不輸出空格或換行。習(xí)慣寫法:不讓自定義類型的輸出函數(shù)隨便輸出空格或換行。再定義一個(gè)輔助性的輸出函數(shù),在前后分別輸出一個(gè)字符串:voidprtCx2(constchar*str1,Complexx,constchar*str2){cout<<str1;prtCx(x);cout<<str2;}從標(biāo)準(zhǔn)輸入流輸入復(fù)數(shù)的函數(shù)似乎可以簡單設(shè)計(jì)如下:voidreadCx(Complexcx){cin<<cx.re<<cx.im;returncx;}此函數(shù)既不友好,也不健壯。輸入函數(shù)應(yīng)該完成如下操作:(1)輸出提示信息,讓用戶知道需要進(jìn)行輸入操作;(2)接收用戶的輸入;(3)告知系統(tǒng),輸入是否成功。以指針為參數(shù)的輸入函數(shù)可以定義為:intreadCx(constchar*prompt,Complex*pcx);

提示信息字符串

指向復(fù)數(shù)類型的指針返回值的設(shè)計(jì)仿照標(biāo)準(zhǔn)庫的輸入函數(shù):成功讀入時(shí)返回

1,失敗時(shí)返回

0,遇到文件結(jié)束或者其他錯(cuò)誤時(shí)返回

EOF

值。72輸入函數(shù)的具體實(shí)現(xiàn)依賴于對輸入形式的設(shè)計(jì)。例如:intreadCx(constchar*prompt,Complex*pcx){cout<<prompt;//輸出提示信息if(cin>>pcx->re&&cin>>pcx->im)//接受用戶輸入return1;//輸入成功時(shí)返回1elsereturn0;//輸入成功時(shí)返回0}此函數(shù)中約定的復(fù)數(shù)輸入形式就是順序輸入其實(shí)部和虛部,兩部分之間用空白字符分隔。73至此,一個(gè)基本的復(fù)數(shù)計(jì)算函數(shù)庫就完成了。它包括:表示復(fù)數(shù)的結(jié)構(gòu)體類型“Complex”實(shí)現(xiàn)復(fù)數(shù)算術(shù)運(yùn)算的函數(shù):addCx,subCx,tmsCx,divCx基本的輸出和輸入函數(shù):prtCx,prtCx2,readCx基于上面這些內(nèi)容,可以編寫處理復(fù)數(shù)數(shù)據(jù)的程序。例如,寫一個(gè)測試以上函數(shù)的主函數(shù):intmain(){Complexc1,c2,c3,c4;//定義復(fù)數(shù)變量doublere,im;

//輸入兩個(gè)實(shí)數(shù)以創(chuàng)建c1cout<<"輸入兩個(gè)實(shí)數(shù)用于創(chuàng)建復(fù)數(shù)c1:";if(

!(cin>>re>>im)){cout<<"輸入出錯(cuò)!程序終止。\n";exit(1);}c1=createCx(re,im);prtCx2("c1=",c1,"\n");74//使用輸入函數(shù)創(chuàng)建c2if(!readCx("輸入c2的實(shí)部和虛部:",&c2)){cout<<"輸入出錯(cuò),程序終止。\n";exit(1);}prtCx2("c2=",c2,"\n");c3=addCx(c1,c2);

//復(fù)數(shù)加法

prtCx2("c3=c1+c2=",c3,"\n");c4=divCx(c1,c2);//復(fù)數(shù)除法

prtCx2("c4=c1/c2=",c4,"\n");return0;}讀者還可以擴(kuò)充這個(gè)函數(shù)庫的功能,增加其他有用的函數(shù),并寫出更復(fù)雜的程序。75小結(jié):“8.3.1復(fù)數(shù)的表示和處理”展示了“自底向上”程序開發(fā)模式:76數(shù)據(jù)類型基本函數(shù)主程序表示復(fù)數(shù)的結(jié)構(gòu)體類型“Complex”復(fù)數(shù)算術(shù)運(yùn)算函數(shù),輸出輸入函數(shù)778.3.2學(xué)生成績管理系統(tǒng)【例6-21】寫一個(gè)程序,通過輸入(或從文件中讀?。┑玫?/p>

N

個(gè)(N≤200)學(xué)生的一門課的成績。首先分別輸出不及格的成績和及格的成績,然后輸出不及格和及格的人數(shù),再計(jì)算出平均成績值

M

和標(biāo)準(zhǔn)差

S,最后輸出一個(gè)分段成績的直方圖?!纠?-6】現(xiàn)在考慮用結(jié)構(gòu)體重新實(shí)現(xiàn)前文(6.6.2節(jié))中的學(xué)生成績管理系統(tǒng)。希望其功能更加完備:輸入學(xué)生信息輸入學(xué)生成績保存學(xué)生信息和成績到數(shù)據(jù)文件讀取已有的學(xué)生信息數(shù)據(jù)文件并允許修改功能參量保存到參數(shù)配置文件以供下次讀取除了作為結(jié)構(gòu)體的編程實(shí)例外,還想通過這一實(shí)例介紹實(shí)際編程中的一些情況和常用技術(shù)。原有程序僅處理一門課程的一次考試成績,缺乏實(shí)用性。程序中應(yīng)該同時(shí)記錄每個(gè)學(xué)生的信息(常用的是學(xué)號、姓名、性別和出生年份)才行。為此需要在程序中定義一種結(jié)構(gòu)體類型,包含:學(xué)生的信息(常用的是學(xué)號、姓名、性別和出生年份)課程成績(這里只考慮一門課程的成績,包括平時(shí)成績、期末考試成績和總評成績)。在此對每一項(xiàng)數(shù)據(jù)都要進(jìn)行事先分析。7879學(xué)號:定義為整數(shù)類型(特殊情況下需定義為字符數(shù)組)學(xué)生的姓名肯定是字符串,但是長度不一,而且可能有空格。為了簡化任務(wù),選用定長字符數(shù)組存儲(chǔ)。長度設(shè)為21個(gè)字符(可存儲(chǔ)10個(gè)漢字)。讀寫時(shí)要注意空格。性別:選用字符類型,用‘M’或‘F’表示。出生年份,用整數(shù)表示。平時(shí)成績、期末考試成績和總評成績用浮點(diǎn)數(shù)float類型。typedefstructStuRec{intno;//學(xué)號

charname[21];//姓名

chargender;//"性別"的英文單詞為genderintbirthyear;//出生年份

floatscore1,score2,score3;//平時(shí)成績、期末考試成績和總評成績

}StuRec;研究并確定在這個(gè)軟件系統(tǒng)的工作中需要保存的信息。實(shí)用的軟件系統(tǒng)運(yùn)行中需要記錄的信息可以分為兩類:是程序工作中需要處理和使用的數(shù)據(jù),在本問題中就是一批學(xué)生的信息和成績。這些信息應(yīng)該允許用戶輸入和修改,并且應(yīng)該能存儲(chǔ)到一個(gè)文件中,可以下一次運(yùn)行時(shí)再次讀取和使用。程序運(yùn)行的參量(功能參量)。應(yīng)該允許用戶在程序運(yùn)行中設(shè)置具體參量值,而且,程序退出時(shí)應(yīng)保存到文件。相應(yīng)文件名通常在編程時(shí)設(shè)定并固定不變,本例中命名為“config.ini”,讓程序在每次啟動(dòng)時(shí)自動(dòng)從這個(gè)文件中讀取相關(guān)的信息。這兩類信息既有聯(lián)系又有區(qū)別,需要合理劃分。80首先考慮程序的功能參量。本程序中處理的學(xué)生信息和成績要保存到指定的文件里。定義一個(gè)全局的字符串作為數(shù)據(jù)文件名:chardatafile[256]="students.txt";//數(shù)據(jù)文件名該數(shù)據(jù)文件中最大能存儲(chǔ)多少個(gè)學(xué)生的記錄。定義一個(gè)表示最大學(xué)生數(shù)量的變量:intmaxnum=400;//最大學(xué)生數(shù)量程序中用于繪制統(tǒng)計(jì)直方圖的量也屬于功能參量:inthistohigh=60,seglen=5;//最大高度和間隔寬度inthistonum=(100/seglen)+1;//直方圖的間隔數(shù)81然后考慮需要保存的數(shù)據(jù)信息。對于待管理的學(xué)生信息和成績數(shù)據(jù),程序有必要記錄學(xué)生的學(xué)校、院系和班級信息,定義一個(gè)全局變量

title:chartitle[256]="某某大學(xué)某某學(xué)院20xx級某某專業(yè)";用一個(gè)全局變量

studnum

表示實(shí)際學(xué)生數(shù):intstudnum=0;//實(shí)際學(xué)生數(shù)(初始化為0)程序中輸入平時(shí)成績和期末考試成績,自動(dòng)用這兩項(xiàng)成績按事先確定的比重算出總評成績,而且按照指定的及格分?jǐn)?shù)線分別統(tǒng)計(jì)。定義平時(shí)成績所占比重的全局變量rate1,表示及格分?jǐn)?shù)的全局變量passline:doublerate1=0.4;

//平時(shí)成績比重,期末比重為1-rate1doublepassline=60;//及格分?jǐn)?shù)線82程序在工作中需要處理一批學(xué)生的信息和成績,采用動(dòng)態(tài)分配的結(jié)構(gòu)體數(shù)組,定義一個(gè)全局性的結(jié)構(gòu)體指針:StuRec*stud;//全局性的學(xué)生記錄結(jié)構(gòu)體指針可用如下語句動(dòng)態(tài)申請存儲(chǔ)和動(dòng)態(tài)釋放存儲(chǔ):stud=newStuRec[maxnum];//動(dòng)態(tài)申請存儲(chǔ)delete[]stud;//動(dòng)態(tài)釋放存儲(chǔ)以上幾項(xiàng)數(shù)據(jù)都與系統(tǒng)中處理的學(xué)生信息和成績相關(guān),但是仔細(xì)分析,可以看到它們實(shí)際上分為兩類:title、studnum、rate1

passline

是整體性參數(shù),可以稱為數(shù)據(jù)參數(shù);用

stud

所指的學(xué)生記錄數(shù)組才是程序處理的實(shí)際的學(xué)生信息和成績。8384有了上面的基本設(shè)計(jì),下面就可以考慮程序的整體功能了。學(xué)生成績管理系統(tǒng)的主要功能可以讓用戶輸入學(xué)生的信息和成績,輸入時(shí)應(yīng)該可以批量逐個(gè)輸入或者個(gè)別修改。程序每次啟動(dòng)時(shí)都應(yīng)該能夠讀入原有文件中的數(shù)據(jù)。還應(yīng)該允許用戶修改一些參數(shù)(成績比例和及格分?jǐn)?shù)),這些參數(shù)事先存儲(chǔ)在參數(shù)配置文件config.ini中。學(xué)生的信息管理和成績管理是在兩個(gè)不同時(shí)段進(jìn)行的:在課程授課階段錄入學(xué)生信息(這時(shí)把學(xué)生成績都賦為-1,以指示并未錄入成績),期末考試之后錄入學(xué)生成績。而且在錄入學(xué)生信息或成績時(shí)可能是批量進(jìn)行的,或單獨(dú)增加和修改的。因此,可以設(shè)想,程序的主要流程如下:從參數(shù)配置文件中讀取參數(shù);顯示如下菜單:

1.批量輸入學(xué)生信息

2.單獨(dú)增加/修改學(xué)生信息

3.批量輸入學(xué)生成績

4.單獨(dú)增加/修改學(xué)生成績

5.列出所有學(xué)生信息和成績

6.成績統(tǒng)計(jì)分析

7.修改參數(shù)

0.退出用戶輸入菜單項(xiàng)數(shù)字,執(zhí)行相應(yīng)的功能;保存各項(xiàng)參數(shù)到配置文件并退出;8586大致地寫出主函數(shù)的內(nèi)容:intmain(){cout<<"====學(xué)生成績管理系統(tǒng)===="<<endl;

readConfig();//從功能參數(shù)配置文件中讀取參數(shù)(初次使用就設(shè)置參數(shù))

readData();//讀取數(shù)據(jù)文件

showPara();//顯示程序功能參數(shù)和數(shù)據(jù)參數(shù)intchoose=-1;while(choose!=0){cout<<"====學(xué)生成績管理系統(tǒng)===="<<endl;cout<<"1.批量輸入學(xué)生信息"<<endl;cout<<"2.修改學(xué)生信息"<<endl;cout<<"3.批量輸入學(xué)生成績"<<endl;cout<<"4.修改學(xué)生成績"<<endl;87cout<<"5.列出所有學(xué)生信息和成績"<<endl;cout<<"6.成績統(tǒng)計(jì)分析"<<endl;cout<<"7.修改參數(shù)"<<endl;cout<<"0.退出"<<endl;cout<<"========================"<<endl;cout<<"請選擇程序功能(1-7,0):";while(!(cin>>choose)||choose<0||choose>7){cin.clear();cin.sync();cout<<"輸入錯(cuò)誤。請重新選擇程序功能(1-7,0):";}cin.sync();switch(choose){case1:inputStud();break;//1.批量輸入學(xué)生的信息case2:modifyStud();break;//2.單獨(dú)增加/修改學(xué)生信息case3:inputScore();break;//3.批量輸入學(xué)生成績case4:modifyScore();break;//4.單獨(dú)增加/修改學(xué)生成績case5:showData();break;//5.列出所有學(xué)生信息和成績case6:statistic();break;//6.成績統(tǒng)計(jì)分析

溫馨提示

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

最新文檔

評論

0/150

提交評論