從問題到程序設(shè)計與語言引論_第1頁
從問題到程序設(shè)計與語言引論_第2頁
從問題到程序設(shè)計與語言引論_第3頁
從問題到程序設(shè)計與語言引論_第4頁
從問題到程序設(shè)計與語言引論_第5頁
已閱讀5頁,還剩33頁未讀 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

第十章C語言里的一些主要機制以及寫程序的各種基本技術(shù),討論一分別編譯和C和習題中問題更復雜得多。隨著程序變得越來越大,許多新問題也隨之出現(xiàn)了。的頭文件,因為存在許多無法解決的,為此人們考慮了采用多個源文件開發(fā)一個程序采用多個源程序文件開發(fā)一個程序的過程通常稱為分塊開發(fā)。分塊開發(fā)得到C語言程序加工過程的支持,因為C語言允許加工對象不是完整的程序,而是一個個的源程序文件。件。第五章的圖5.5描述了這種開發(fā)過程的基本情況。unitsC語言里做分塊開發(fā),需要C系統(tǒng)的預處理功能,以達到對源程序的適當物理劃分,并設(shè)法保證組成同一個程...

zhangshan8680lisi7790#include<stdio.h>#include<stdlib.h>#include<math.h>#include<ctype.h>enumMAXNUM=MIDDLE20EXECISE30FINAL50*HISTLEN=60, /*最長行的長度(字符數(shù))*/SEGLEN=5, /*分段長度*/SEGNUM100/SEGLEN+1*/**/typedefstruct{unsignedlongnum;charname[20];doublemid,exe,final,}/*全局性數(shù)據(jù)對象的定義*/StuRecstudents[MAXNUM];主函數(shù)main處理學生記錄文件的打開關(guān)閉:{FILE*fp;charfn[128];do*getnstr("Studentrecordfilename:",128,fn);if((fp=fopen(fn,"r"))==NULL)printf("Can'topenfile:%s\n",fn);else{commander(fp,fn);}}whilereturn}文件,commander首先將文件里的學生成績記錄讀入,而后轉(zhuǎn)入交互命令的處理:{intn,n=readSRecs(fp,MAXNUM,students);if(n<=1){printf("File%s:toofewdataitems.\n",fn);}docmd=getcmd("Cmds:1,Statistics;2,Histogram;""3,Sortandstoretofile\n",1,3);switch(cmd)case1:statistics(n,students);case2:histogram(n,students,SEGLEN);case3:sortoutput(n,students);}}while}intgetcmd(char*prompt,intc1,intcn);intnext(chars[]);voidgetnstr(charprompt[],intlim,char{intdoubles,sum,if(n<=1)printf("Datatoofew.Statisticsstop.\n");}for(sum=0.0,i=0;i<n;++i)sum+=tb[i].score;avr=sum/n;for(sum=0.0,i=0;i<n;sum+=(tb[i].score-avr)*(tb[i].score-avr);s=sqrt(sum/(n-1));printf("Totalstudents:%d\n",n);printf("Averagescore:%lf\n",avr);printf("Standarddeviation:%lf\n\n",s);}{intfor(i=0;i<n;++i)}{inti,intfori0iSEGNUM++isegs[i]0**/for(i=0;i<n;++i)/*統(tǒng)計各分段人數(shù)*/for(mx0i0iSEGNUM++i**/if(segs[i]>mx)mx=segs[i];for(i=0;i<SEGNUM;++i){/*輸出*/printf("<%3d%4d|"i+1)*SEGLEN,segs[i]);}}{charFILEdo*getnstr("Filenameforsaving:",128,fn);if((fp=fopen(fn,"w"))==NULL)printf("Can'topenfile:%s\n",fn);else{qsort(tb,n,sizeof(StuRec),scrcmp);printSRec(fp,n,tb);}}while(next("Reallywantto}intscrcmp(constvoid*vp1,constvoid{StuRec*p1=(StuRec*)vp1,*p2=(StuRec*)vp2;returnp1->score>p2->score?1p1->score==p2->score?0:-}{intfor(i=0;i<limit;fprintf(fp,"%-10lu%20s%6.1f%6.1f%6.1f%6.1f",tb[i].num,tb[i].name,tb[i].mid,tb[i].exe,tb[i].final,tb[i].score);return}staticintcheck(double{returnx>=0.0&&x<=}{charif(fgets(s,256,fp)==NULL)returnif(sscanf(s,"%lu%s%lf%lf%lf",&stp->num,stp->name,&stp->mid,&stp->exe,&stp->final)==5){stp->score=(stp->mid*MIDDLE+stp->exe*EXECISE+stp->final*FINAL)/100;return}return}{inti=0,line=1,n;doublex;while(i<limit&&(n=readrec(fp,&tb[i]))!={if(n==printf("Dataerror,line%d\n",line);else++i;}if(i==limit&&!feof(fp)){/*還有數(shù)據(jù)*/printf("ToomanydataOutputisnotcorrect.\n");return0;}return}sscanf分析和賦值。如果一行的信息#include包含了幾個標準庫頭文C程序的典型情況:程序包含了若干標準庫(或其他庫)頭StuRec一組函數(shù);完成對成績記錄的各種處理的函數(shù);還有若干輔助性的功能函數(shù),如next、編譯,最終能連接為一個有機的完整程序。是為其他文件提供信息。這個頭文件命名為stu.h,其內(nèi)容如下:/*filestu.hstu*/#include<stdio.h>#include<stdlib.h>#include<math.h>#include<ctype.h>enum{MAXNUM=MIDDLE20EXECISE30FINAL50*HISTLEN=60, /*最長行的長度(字符數(shù))*/SEGLEN=5, /*分段長度*/SEGNUM100/SEGLEN+1*/**/typedefstructunsignedlongnum;charname[20];doublemid,exe,final,}/**/externStuRecstudents[];intreadSRecs(FILE*fp,intlimit,StuRectb[]);intprintSRec(FILE*fp,intlimit,StuRectb[]);voidhistogram(intn,StuRectb[],inthigh);voidsortoutput(intn,StuRectb[]);intnext(charvoidgetnstr(charprompt[],intlim,charbf[]);intgetcmd(char*prompt,intc1,intcn);/*filestu.cstu*/#include"stu.h"StuRecstudents[MAXNUM];voidcommander(FILE*fp,char*fn) /*filestu_io.cstu*/#include"stu.h"staticintcheck(doublex) /*filestu_fun.cstu*/#include"stu.h" staticvoidprtHH(intn) voidhistogram(intn,StuRectb[],inthigh) staticintscrcmp(constvoid*vp1,constvoid*vp2) /*fileutilities.cstu*/#include"stu.h"intnext(chars[]) voidgetnstr(charprompt[],intlim,charbf[]) intgetcmd(char*prompt,intc1,intcn) 10.1stu.h/*/*filestu.h,stu*/#include<stdio.h>#include<math.h>#include<ctype.h>enumMAXNUM=...typedefstruct{...}.../*filestu_ioc,stu#include"stu.h"staticint/*filestu_ioc,stu#include"stu.h"staticintcheck(double])S)#includestu.h"])S)

/*filestu_fun.c,intmain(void){...

#includetotovoidsortoutput(intn,

#includeintnext(chars[]) lim,charvoidgetnstr(charlim,char intgetcmd(char*prompt,intc1,int 10.1stu.h里包含了程序所需的所有標準頭文件,這就使所有源程序功能,因此可能需要#include許多標準頭文件。然而,并不是每個源程序文件都需要用/*filestu.h程序stu*/enum{MAXNUM=MIDDLE20EXECISE30FINAL50*HISTLEN=60, /*最長行的長度(字符數(shù))*/SEGLEN=5, /*分段長度*/SEGNUM100/SEGLEN+1*typedef{unsignedlongnum;charname[20];doublemid,exe,final,}externStuRecintreadSRecs(FILE*fp,intlimit,StuRecintprintSRec(FILE*fp,intlimit,StuRectb[]);voidstatistics(intn,StuRectb[]);voidhistogram(intn,StuRectb[],inthigh);voidsortoutput(intn,StuRectb[]);intnext(charvoidgetnstr(charprompt[],intlim,charbf[]);intgetcmd(char*prompt,intc1,intcn);/*filestu.c程序stu**/#include<stdio.h>StuRecvoidcommander(FILE*fp,char*fn) 的方式是將包含標準庫頭文件令寫面。C語言中靜態(tài)函數(shù)和靜態(tài)機制在開發(fā)大程序中的作用。的定義和使用將處在不同文件里。C語言對許多情況并不強制性地要求做嚴格檢查,如果我C程序的人們通常把一個程序的源文件分成兩類,一類是包含實際程文件提供信息的文件以.h為擴展名,稱為頭文件、head文件,或簡稱為h文件。C語言系統(tǒng)本身的實現(xiàn)也遵循這一方式。一個C語言系統(tǒng)總為我們提供了一組標準庫這些頭文件的作用就是為在C程序里使用標準庫函數(shù)以及其他功能提供必要的信息。如果原型說明;變量的外部說明(關(guān)鍵字extern引導的說明,而不是變量定義,僅說明這時仍應該堅持這里各項原則。*庫函數(shù)的實際代碼存在另外的庫文件里。在對目標程序連接時,連接程序?qū)奶囟◣煳募锶〕鲇嘘P(guān)代碼段,拼裝到最終的可執(zhí)行程序里,形成完整的程序。這是目前大部分C語言系統(tǒng)的通行實現(xiàn)方式。#include命令做文件包含。如果在許多地方都使用同一個標準#include命令寫在某數(shù)應定義為靜態(tài)的(static關(guān)鍵字#include命令界面的應用程序(Windows系統(tǒng)下的開發(fā),Unix將所需的C源程序文件加入這一項目中(IDE提供了專門命令或者其他方式。通IDE環(huán)境中開發(fā)前面的學生成績處理系統(tǒng),我們可以創(chuàng)建一個項目, 接前重新編譯必要的文件,保證所生成的可執(zhí)行程序總能反映整個項目的修改情況,等(compilelink完整的可執(zhí)行程序文件。有些IDE在連接時會檢查現(xiàn)存的目標文件是否都為的,(make程序已經(jīng)是版本了,那么它就什么也不做。all介紹反應了各種IDE的一般性情況,可供參考。

10.2

中心,如果我們需要修改文件yyy.c中的某個函數(shù)f定義的頭部,而文件xxx.c里使用了f,那么f的原型一定已經(jīng)寫在文件xxx.h里,需要修改以便與yyy.c中的定義保持一致。由于所有源程序文件都依賴于頭文件xxx.h,因此它們都受到了影響,至少是都需要重新編

頭文件文件 10.3

舉例來說,面學生成績處理的例子里,源文件utilities.c里定義了一些常用的功能utilities.hutilities.c與使用該文件提供的功能的程序文件之間的信息通道。下面是utilities.h:/*utilities.h,*/#include<stdio.h>intnext(charvoidgetnstr(charprompt[],intlim,charbf[]);intgetcmd(char*prompt,intc1,intcn);/*utilities.c,*/#include"utilities.h"intnext(chars[]) voidgetnstr(charprompt[],intlim,charbf[]) intgetcmd(char*prompt,intc1,intcn) /*filestu.h程序stu*/enum{MAXNUM=MIDDLE20EXECISE30FINAL50*HISTLEN=60, /*最長行的長度(字符數(shù))*/SEGLEN=5, /*分段長度*/SEGNUM100/SEGLEN+1*typedef{unsignedlongnum;charname[20];doublemid,exe,final,}externStuRecintreadSRecs(FILE*fp,intlimit,StuRectb[]);intprintSRec(FILE*fp,intlimit,StuRecvoidstatistics(intn,StuRecvoidhistogram(intn,StuRectb[],inthigh);voidsortoutput(intn,StuRectb[]);/*filestu.c程序stu**/#include<stdio.h>#include"stu.h"#include"utilities.h"StuRecvoidcommander(FILE*fp,char*fn) 們修改文件utilities.c中函數(shù)

10.4intreadSRecs(FILE*fp,intlimit,StuRectb[]);#include<stdio.h>#include<math.h>voidhistogram(intn,StuRectb[],int讓這兩個源程序文件分別包含自己的頭文件和stu.h,讓主文件也包含這兩個新的頭文件。utilities.c所提供的功能可能用到許多其他交互式程序里。采用在需要時將它們可能需要的輔助函數(shù)(應該定義為static函數(shù)些外部變量(根據(jù)需要考慮是否定義為static變量;文件complex.h可以是下面的樣子(具體設(shè)計可以根據(jù)實際需要:/*complex.h/*類型定義*/typedefstructdoublere,}/*externconstComplexComplex0;externconstComplexComplex1;externconstComplexComplexI;/* plex(doublere,doubleim); plex(doubled); /*Complexplex(Complexx,Complexy);Complexplex(Complexx,Complexy);Complexplex(Complexx,Complexy);Complexplex(Complexx,Complexy);/*/*intplex(Complexx,Complex/* plex(FILE*fp,Complex*xp); plex(FILE*fp,Complexx);/*complex.c*/#include<stdio.h>/*constComplexComplex0={0,constComplexComplex1={1,constComplexComplexI={0,/* plex(intn) /* /*/* plex(Complexx,Complexy) /* plex(FILE*fp,Complexx) complex.c加入其開發(fā)項目,需要使complex.ccomplex.h加工的,因此,這個頭文件就成了維系complex.c與其未來使用者之間一致性的紐帶。complex.h描述們(由于某種原因)complex.h中各種函由于C語言是1970年發(fā)的語言,那時人們對于數(shù)據(jù)類型封裝和模塊封裝的認識還C語言里完成這些構(gòu)造,需要借助于一些編程約定和預處理功能(如上仔細想想不難發(fā)現(xiàn),一旦complex.c做好,那些使用這個文件中所定義的功能的時不修改了這個文件,造成錯誤的可能性。complex.hcomplex.c編譯后生成的目標文件。別人C系統(tǒng)將標準庫的所有各種C語言系統(tǒng)通常都提供了創(chuàng)建庫文件的功能,例如提供可將目標文件轉(zhuǎn)換為庫文10.1.7#if!defined(MY_HEAD_FILE1)#defineMY_HEAD_FILE11MY_HEAD_FILE1就printf實現(xiàn)的。也正因為此,許多源程序文件都需要包含標準庫printf("Can'topenfile:%s\n",fn);printf("Datatoofew.Statisticsstop.\n");printf("Dataerror,line%d\n",line);printf的格式化功能生成實際的輸出消息串。寫好一個能滿足這樣多種需要的{}調(diào)用fprintf輸出錯誤信息。emessageutilities.cprintf到的一條通道中,比較容易統(tǒng)一地了。{}printf("Can'topenfile:%s\n",fn);printf("Datatoofew.Statisticsstop.\n");printf("Dataerror,line%d\n",此它需要有類似printf的參數(shù)形式和功能:可以用一個“格式串”描述輸出消息的框可以根據(jù)需要變化。此外,我們還希望用emessage將錯誤消息的輸出目標和基本形式隱在變參數(shù)函數(shù)里,需要借助于<stdarg.h>valist和其他相關(guān)功能,valistvl**/va_start(vl,estr);}emessage的定義并沒有本質(zhì)性的困難,關(guān)心具體寫法的讀者可以自己考慮,可以參考《C程序設(shè)計語言》中有關(guān)一個簡化版本的printf實現(xiàn)的討論,這里不仔細討論了。我們想在這里順便介紹另一組輸出函數(shù),借助于它們可以簡化實現(xiàn)。這組函數(shù)的介紹參看第11.8節(jié),它們的功能與普通printf、fprintfsprintf...,而是一{valistvl;va_start(vl,estr);fprintf(stderr,"\nError:");vfprintf(stderr,estr,vl);fputc('\n',stderr);}emessage("Can'topenfile:%s\n",fn);emessage("Datatoofew.Statisticsstop.\n");emessage("Dataerror,line%d\n",line);printf函數(shù)族的格式化功能,這使函數(shù)定義大大簡化。如果需要,我{scanf("%d",}一塊可見,其中能存放n個整數(shù),就可以寫:intn,*p;p=(double*)malloc(n*量n可能沒有得到合法值,隨后的分配就完全沒有保證了。voidgetnum(int*np)if(scanf("%d",np)!=1)printf("Can'treadanumber!\n");}voidgetnum(int*np)if(scanf("%d",np)!={printf("Can'treadanumber!\n");exit(1);}}getchar返回空指針值NULL表示出現(xiàn)了問題。這時同樣可以通過上述函數(shù)檢查實際情況。double00。C語言C語言系統(tǒng)可以自己確定。但標準規(guī)定至少數(shù)作一個變量,其具體實現(xiàn)由C系統(tǒng)確定,第11.1節(jié)說明了errno的一般使用方法。 {Complexdoubleden=y.re*y.re+y.im*if(den=={errno=ERANGE;c.re=1;c.im=0;}elsec.re=(x.re*y.re+x.im*y.im)/den;c.im=(x.im*y.re-x.re*y.im)/}return}許多研究,提出了一些新的概念和機制,并將它們納入某些新語言(Ada、C++和Java{inti;doubles=0.0;for(i=0;i<n;++i)s+=a[i];returns/n;}x=avrg(m,{inti;doubles=0.0;if(n==0)returnfor(i=0;i<n;++i)s+=a[i];returns/n;}if(n<=0)return(preondition,(postcondition0,調(diào)用代碼段就應該注意到這種可能性,檢查出現(xiàn)0的情況并適當處理。用另一個標準函數(shù)abort終止程序。{inti;doubles=0.0;assert(n>for(i=0;i<n;++i)s+=a[i];returns/n;}函數(shù)prtHH:{intfor(i=0;i<n;++i)}數(shù)調(diào)用的情況prtHH。在這里增加檢查,除了增加執(zhí)行開銷之外就沒有什么收獲。排除錯誤造成的極大。這種做法在大程序開發(fā)中也是非常有價值的。MAXNUMSEGNUM可以由其他參量算出,因此它不是獨立的,但也可以將它放在這里統(tǒng)一處理。在一students改為指針,動態(tài)分配學生記錄的空間。修改后的頭文件將是:/*filestu.h程序stu*/#include<stdio.h>#include<stdlib.h>#include<math.h>#include<ctype.h>externintMIDDLEEXECISEFINAL*HISTLEN*最長行的長度(字符數(shù))*/SEGLEN,/*分段長度*/SEGNUM;/*typedef{unsignedlongnum;charname[20];doublemid,exe,final,}intreadSRecs(FILE*fp,intlimit,StuRectb[]);intprintSRec(FILE*fp,intlimit,StuRectb[]);voidstatistics(intn,StuRectb[]);voidhistogram(intn,StuRectb[],inthigh);voidsortoutput(intn,StuRectb[]);intnext(charvoidgetnstr(charprompt[],intlim,charbf[]);intgetcmd(char*prompt,intc1,intcn);段的事實(由于SEGLEN是整數(shù)int,intinit(intargc,char**{FILE*fp;emessage("Initiationfails.Stopprogram.\n");return1;}...}{intprintf("Pleasegivethreeratio:middleexecisefinal>");n=scanf("%d%d%d",&MIDDLE,&EXECISE,&FINAL); students=(StuRec*)calloc(MAXNUM,sizeof(StuRec));return1;}位于允許范圍。只有在正常完成所有參數(shù)的初始化的情況下,init1,否則就返回是為了下面討論其他定義方式時不必修改initmain的原型。)intMAXNUM=MIDDLE20EXECISE20FINAL50*HISTLEN=60, /*最長行的長度(字符數(shù))*/SEGLEN=5, /*分段長度*/SEGNUM boolinit(intargc,char**argv)...}:N500E30M20F50H40認值。這樣,基本的init函數(shù)定義可以采用如下形式:{while(*++argv!=0){char*p=*argv;{caseMAXNUM=atoi(++p);break;case'E':EXECISE=atoi(++p);break;case'M':MIDDLE=atoi(++p);break;case'F':FINAL=atoi(++p);break;case'H':HISTLEN=atoi(++p);break;case'L':SEGLEN=atoi(++p);break;emessage("Unrecognizedcommand-lineargument:%c\n",*p);return0;}}/*做一些檢查if(EXECISE+MIDDLE+FINAL!=100)/*輸出錯誤信息并返回0}/**/SEGNUM=100/SEGLEN+1;students=(StuRec*)calloc(MAXNUM,sizeof(StuRec));return1;}數(shù)。上面init函數(shù)里直接使用了Catoi,它由表示整數(shù)的數(shù)字字符序列得將指針p向前移一個字符,才能使它指向數(shù)字字符串的開始。UNIX字符。這樣,在分析一個命令行參數(shù)時,只需看一個字,功能參數(shù)。這種文件的名字常常以.ini或者.cfg等為擴展名,稱為軟件系統(tǒng)的初始化文 next描述的。程序里的函數(shù)調(diào)用關(guān)系形成了一種分層,構(gòu)成了程序的分層邏輯結(jié)構(gòu)。整個程序分解為一些基本部分。在C語言里就是分解為一些實現(xiàn)程序的各部分功能的函系和需要交換的信息會有所不同main函數(shù)見10.1節(jié)。編譯通過之后,我們還沒辦法運行,因為缺少main需要調(diào)用的一些部分。假設(shè)next和utilities.cstu.hcommander完全是新的東西,沒有它就無法進行程序連接(連接時將出現(xiàn)“commander沒有定義”一類的錯誤信息commander寫出來,因為如果那樣做,同樣問題又會出現(xiàn)在commander里,如此下去就只能把所有函數(shù)都定義好,然后在編譯運行和調(diào)試了。voidcommander(FILE*fp,char*fn){因為commander不返回值,用一個空函數(shù)體,就能和main等等一起構(gòu)成一個“完整的”{charline[128];printf(

溫馨提示

  • 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

提交評論