版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
從問題到程序裘宗燕北京大學(xué)數(shù)學(xué)學(xué)院2005年1第八章
文件與輸入輸出機(jī)試系統(tǒng)名單已導(dǎo)入031112031113031121用戶名及密碼均為學(xué)號(hào)訪問地址為::8080/xdoj/2文件概念C程序中的文件使用結(jié)合介紹計(jì)算機(jī)及程序中一些相關(guān)問題和概念C語(yǔ)言標(biāo)準(zhǔn)庫(kù)中的輸入輸出函數(shù)輸入輸出中的格式控制問題交互式程序的概念和相關(guān)問題38.1文件概念輸入、輸出和文件功能解決程序處理的數(shù)據(jù)來(lái)源和結(jié)果的保存問題。程序里的變量至多存在到程序結(jié)束。程序中積累的信息不能通過(guò)變量帶到下次執(zhí)行程序啟動(dòng)時(shí)OS為其分配存儲(chǔ)。程序結(jié)束后該存儲(chǔ)區(qū)可能分配給其他程序內(nèi)存的特性:關(guān)機(jī)后存儲(chǔ)其中的數(shù)據(jù)立刻消失為“持續(xù)”保存數(shù)據(jù),必須借助外存,磁盤、磁帶等語(yǔ)言需提供訪問和使用外存的能力。文件是外存數(shù)據(jù)組織的基本單元。4外存數(shù)據(jù)組織在目錄、文件結(jié)構(gòu)中。目錄是子目錄和文件的集合,文件是封裝的數(shù)據(jù)體。目錄、文件通過(guò)名字使用。與外存交換信息主要就是訪問文件。從程序向外送信息是輸出,由外部取信息是輸入。OS通常把所有IO對(duì)象都統(tǒng)一到文件的概念,包括外存文件和各種IO設(shè)備(鍵盤、顯示器、打印機(jī)等)。鍵盤、顯示器等設(shè)備也看作文件,給定“文件名”,有關(guān)操作都通過(guò)相應(yīng)的文件名實(shí)施。IO工作繁雜瑣碎,依賴于運(yùn)行環(huán)境。語(yǔ)言需處理有關(guān)問題、屏蔽細(xì)節(jié)、以利編程,是程序語(yǔ)言設(shè)計(jì)的難點(diǎn)5C語(yǔ)言本身無(wú)支持IO的結(jié)構(gòu)或者機(jī)制,通過(guò)庫(kù)提供IO具體C系統(tǒng)可提供自己的IO功能。ANSIC把IO納入標(biāo)準(zhǔn)庫(kù),以提高可移植性。標(biāo)準(zhǔn)庫(kù)IO基于文件概念,定義了相關(guān)數(shù)據(jù)結(jié)構(gòu)和一組IO函數(shù)。文件IO采用流概念。IO的對(duì)象是文件,為與文件交換信息就需要與之建立聯(lián)系,流就是這種聯(lián)系。要從文件輸入,需要?jiǎng)?chuàng)建與文件關(guān)聯(lián)的輸入流。向文件輸出要?jiǎng)?chuàng)建輸出流。還可能創(chuàng)建輸入輸出流建立聯(lián)系(創(chuàng)建流)的操作稱作打開文件,文件打開后就可以對(duì)它操作。一個(gè)文件不再用時(shí)可以切斷聯(lián)系(撤消對(duì)應(yīng)的流),稱為關(guān)閉文件打開、關(guān)閉是文件處理的基本操作6流分為兩類:正文流(字符流)和二進(jìn)制流。正文流:文件是字符行的序列。一行包含0個(gè)或多個(gè)字符,每行最后有換行符'\n'正文流適合一般IO,包括與人交互的IO二進(jìn)制流:把文件看成字節(jié)的序列。二進(jìn)制流操作保證信息寫入文件后按同樣方式讀回,內(nèi)容不會(huì)改變主要用于程序內(nèi)部數(shù)據(jù)的直接保存和裝入,在保存裝入大批數(shù)據(jù)時(shí)速度快,避免轉(zhuǎn)換引起的信息損失通過(guò)二進(jìn)制流保存的文件不適合人閱讀7流通過(guò)特殊數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn):標(biāo)準(zhǔn)庫(kù)定義了一個(gè)類型FILE,其具體定義由實(shí)現(xiàn)確定。FILE中存儲(chǔ)與流操作(IO文件)有關(guān)的信息文件打開操作返回一個(gè)指向FILE的指針(文件指針),代表所建流文件指針類型格式:FILE*對(duì)流的操作都通過(guò)這種FILE指針進(jìn)行可以認(rèn)為文件指針就是流的具體體現(xiàn)文件變量定義格式:FILE*fp;C標(biāo)準(zhǔn)庫(kù)提供一套函數(shù),包括流創(chuàng)建(打開文件)、撤消(關(guān)閉文件),文件讀寫(通過(guò)流對(duì)文件讀寫)等typedef
struct{shortlevel;/*緩沖區(qū)“滿”或“空”的程度*/unsignedflags;/*文件狀態(tài)標(biāo)志*/charfd;/*文件描述符*/unsignedcharhold;/*如無(wú)緩沖區(qū)不讀取字符*/shortbsize;/*緩沖區(qū)的大小*/unsignedchar*buffer;/*數(shù)據(jù)緩沖區(qū)的位置*/
unsignedchar*curp;/*當(dāng)前工作指針*/unsignedistemp;/*臨時(shí)文件,指示器*/shorttoken;/*用于有效性檢查*/}FILE;8程序啟動(dòng)時(shí)自動(dòng)建立三個(gè)文件指針:標(biāo)準(zhǔn)輸入流stdin標(biāo)準(zhǔn)輸出流stdout標(biāo)準(zhǔn)錯(cuò)誤流stderrstdin與OS標(biāo)準(zhǔn)輸入連接stdout與標(biāo)準(zhǔn)輸出連接stderr通常直接與顯示設(shè)備連接,不能重新定向標(biāo)準(zhǔn)輸入輸出操作getchar,scanf,putchar等都是對(duì)這些流(stdin,stdout)進(jìn)行的9標(biāo)準(zhǔn)庫(kù)采用緩沖式
IO。外存(磁盤、磁帶等)速度慢,用成塊方式傳遞數(shù)據(jù)。程序用數(shù)據(jù)的方式不同。為緩和兩者差異,緩沖式IO用一塊存儲(chǔ)區(qū)(緩沖區(qū))作為文件與程序的中介。10打開文件時(shí)為流建立緩沖區(qū)(一般通過(guò)動(dòng)態(tài)存儲(chǔ)分配),文件與程序間數(shù)據(jù)傳遞都通過(guò)緩沖區(qū)進(jìn)行。文件關(guān)閉時(shí)釋放流緩沖區(qū)。雖然程序與文件間有緩沖區(qū),但操作中看不到它的影響(“透明性”),程序就像是直接在與外存打交道?!巴该餍浴彼枷朐谟?jì)算機(jī)領(lǐng)域里非常重要,是許多設(shè)計(jì)的基礎(chǔ)。在許多領(lǐng)域里都能夠看到。例如網(wǎng)絡(luò)傳輸,數(shù)字電話等等。118.2文件的使用通過(guò)重新定向可以將文件作為IO對(duì)象,把與標(biāo)準(zhǔn)設(shè)備(鍵盤、顯示器)連接的標(biāo)準(zhǔn)流轉(zhuǎn)連到指定文件這種做法有很大局限性:形成的定向在程序執(zhí)行中不能改變無(wú)法使用多個(gè)文件(只有流stdin和stdout)為在程序中方便地使用文件,需要利用標(biāo)準(zhǔn)庫(kù)的文件操作函數(shù),通過(guò)建立輸入輸出流的方式使用文件。12文件的打開和關(guān)閉
fopen打開文件,返回FILE指針,通過(guò)這種指針可進(jìn)行各種文件操作。原型:FILE*fopen(constchar*filename,constchar*mode)filename是文件名;mode指明文件打開方式?;痉绞剑?r"按讀方式打開文件,找不到文件則失敗"w"按寫方式打開,文件已有則丟棄原內(nèi)容"a"按添加方式打開或創(chuàng)建文件,在已有部分之后寫"r+"讀更新方式,可以對(duì)文件讀或?qū)?w+"寫更新方式,可寫讀,如文件存在則丟棄原內(nèi)容"a+"添加并可讀方式,從文件尾接著寫13用二進(jìn)制方式時(shí)加b:"rb"、"wb+"、"a+b"以讀寫方式打開文件,使用時(shí)有特殊規(guī)定若文件打開出錯(cuò),fopen返回空指針值關(guān)閉文件用函數(shù)fclose,原型:intfclose(FILE*stream)
關(guān)閉前將輸出流緩沖區(qū)的數(shù)據(jù)送入文件;而后釋放緩沖區(qū)。正常時(shí)返回0,否則返回EOF。能同時(shí)打開的文件數(shù)有限,文件用完后應(yīng)關(guān)閉流程序退出時(shí)所有文件將自動(dòng)關(guān)閉14使用文件的基本編程模式:FILE*fp;fp=fopen("myfile.abc","r");if(fp==NULL){/*處理文件打不開的情況,可能return*/}....../*對(duì)文件的操作*/fclose(fp);文件操作都是與外部打交道,能否正常完成,依賴于外部環(huán)境當(dāng)時(shí)的情況。所以:fopen后應(yīng)檢查函數(shù)返回值,確保后續(xù)操作有效15若想通過(guò)交互輸入文件名,可采用如下程序模式:intmain(){charfname[128];/*注意越界危險(xiǎn)*/FILE*fp;
printf("Filename:");
scanf("%127s",fname);/*讀入不超過(guò)127字符*/if((fp=fopen(fname,"r"))!=NULL){......}......}如果必須得到正確的文件名并正確打開,可用循環(huán)while(1){
printf("Filename:");scanf("%127s",fname);if((fp=fopen(fname,"r"))!=NULL)break;
printf("Filenameerror!\n");}16文件輸入輸出函數(shù)字符IO函數(shù)字符IO函數(shù)fgetc和fputc的原型:intfgetc(FILE*fp) 從流fp讀字符intfputc(intc,FILE*fp)向fp寫字符返回該字符。遇文件結(jié)束fgetc返回EOF,出錯(cuò)時(shí)都返回EOF。返回值是int類型,原因與getchar相同。getc和putc與上述函數(shù)類似,用宏實(shí)現(xiàn)標(biāo)準(zhǔn)流的字符讀寫函數(shù)通常如下定義:#definegetchar()getc(stdin)#defineputchar(c)putc(c,stdout)17程序cat,將命令行參數(shù)作為文件名,順序復(fù)制到標(biāo)準(zhǔn)輸出;無(wú)文件名時(shí)由stdin向stdout復(fù)制:#include<stdio.h>voidfilecopy(FILE*ifp,FILE*ofp){/*文件復(fù)制*/
intc;while((c=getc(ifp))!=EOF)putc(c,ofp);}intmain(intargc,char*argv[]){FILE*ifp;char*name=argv[0];if(argc==1){/*無(wú)參數(shù)情況*/
filecopy(stdin,stdout);return0;}while(*++argv!=NULL)if((ifp=fopen(*argv,"r"))==NULL)
printf("%s,can'topeninputfile:%s\n",name,*argv);else{
filecopy(ifp,stdout);fclose(ifp);}return0;}18例:從鍵盤輸入一些字符,逐個(gè)把它們送到磁盤文件里,直到輸入一個(gè)“#”為止。#include<stdio.h>#include<stdlib.h>main(){FILE*fp;charch,filename[10];
scanf("%s",filename);if((fp=fopen(filename,"w"))==NULL){printf("cannotopenfile\n");exit(0);}
ch=getchar();while(ch!='#'){fputc(ch,fp);
putchar(ch);
ch=getchar();}
fclose(fp);}19格式化IO函數(shù)文件格式化IO函數(shù)fscanf/fprintf的原型:intfscanf(FILE*stream,constchar*format,...);intfprintf(FILE*stream,constchar*format,...);
功能、使用與scanf、printf類似,增加了FILE*參數(shù)。按格式串做數(shù)據(jù)形式的轉(zhuǎn)換,對(duì)指定流操作。三個(gè)圓點(diǎn)(...)是特殊參數(shù)描述形式,表示參數(shù)數(shù)目可變。定義這種函數(shù)用<stdargs.h>,第11章有介紹編譯時(shí)不檢查對(duì)應(yīng)“...”的實(shí)參個(gè)數(shù)、不做類型轉(zhuǎn)換、不檢查錯(cuò)誤/不產(chǎn)生錯(cuò)誤信息。調(diào)用時(shí),格式串后的參數(shù)在類型和個(gè)數(shù)上必須與格式串的轉(zhuǎn)換描述一致!20例2:將一個(gè)磁盤文件中的信息復(fù)制到另一個(gè)磁盤文件中。#include<stdio.h>#include<stdlib.h>main(){FILE*in,*out;charinfile[10],outfile[10];printf("Entertheinfilename:\n");scanf("%s",infile);printf("Entertheoutfilename:\n");scanf("%s",outfile);
if((in=fopen(infile,"r"))==NULL){printf("cannotopeninfile\n");exit(0);}if((out=fopen(outfile,"w"))==NULL){printf("cannotopenoutfile\n");exit(0);}
while(!feof(in))fputc(fgetc(in),out);fclose(in);fclose(out);}21
行式IO函數(shù):以行為單位進(jìn)行輸入或輸出。行IO函數(shù)需要用字符數(shù)組存放輸入或者輸出字符序列。char*fgets(char*buf,intn,FILE*s);buf為字符數(shù)組。由流s讀至多n-1個(gè)字符存入buf,遇換行符結(jié)束,換行符存入數(shù)組。最后放'\0'。正常結(jié)束時(shí)返回buf,文件結(jié)束或出錯(cuò)時(shí)返回空指針。buf應(yīng)至少能容納n個(gè)字符。intfputs(constchar*buf,FILE*s);將buf表示的字符串送到流s,輸出的最后不向流中添?yè)Q行字符(串里可以包含換行)。正常完成時(shí)返回非負(fù)值,出錯(cuò)時(shí)返回EOF值。22例:文件保存了一批單價(jià)和數(shù)量數(shù)據(jù)。寫程序通過(guò)命令行參數(shù)提供文件名,最終輸出貨物的總貨值設(shè)文件數(shù)據(jù)以單價(jià)、數(shù)量形式成對(duì)出現(xiàn),用fscanf讀入。定義函數(shù)nextentry完成一對(duì)數(shù)據(jù)的讀入,它在發(fā)現(xiàn)所有數(shù)據(jù)處理完畢后返回0值。這里沒處理數(shù)據(jù)出錯(cuò)情況,可補(bǔ)充修改。
doublenextentry(FILE*fp){doublepr,num;intn=fscanf(fp,"%lf%lf",&pr,&num);returnn==EOF?0.0:pr*num;}23intmain(intargc,char**argv){doubletotal=0.0,x;FILE*ifp;if(argc==1){/*缺參數(shù),產(chǎn)生錯(cuò)誤信息*/
printf("Missingfilename.Stop!\n");return1;}if((ifp=fopen(argv[1],"r"))==NULL){printf("Can'topen:%s.Stop!\n",argv[1]);return2;}while((x=nextentry(ifp))!=0.0)total+=x;printf("Totalprice:%f\n",total);
fclose(ifp);return0;}函數(shù)形參char*argv[]和char**argv可以通用,因?yàn)樗鼈儼l(fā)生在數(shù)組調(diào)用過(guò)程中,而在數(shù)組定義過(guò)程中,必須按照規(guī)定格式進(jìn)行,如:
char*name={“aa”,“bb”};//定義在以后調(diào)用過(guò)程中,完全可以寫成:
char**pp=name;char*p[]=name;等形式。24二進(jìn)制流和直接IO函數(shù)格式化函數(shù)fscanf、fprintf工作時(shí),要做內(nèi)外部形式之間的轉(zhuǎn)換。如int內(nèi)部是二進(jìn)制序列,實(shí)際輸出的是一串?dāng)?shù)字字符。格式化輸入函數(shù)也要做轉(zhuǎn)換數(shù)據(jù)轉(zhuǎn)換要耗費(fèi)時(shí)間。如IO對(duì)象是人,就必須進(jìn)行轉(zhuǎn)換。若是要輸出到文件,以便后來(lái)取回程序使用,轉(zhuǎn)換就沒必要了轉(zhuǎn)換還可能丟失信息,尤其是對(duì)浮點(diǎn)(double等)數(shù)據(jù),輸出后再輸入可能產(chǎn)生誤差。為解決這些問題,標(biāo)準(zhǔn)庫(kù)提供二進(jìn)制流和直接IO函數(shù)25如果程序里需要把保存起一些內(nèi)部信息,以便隨后使用或下次執(zhí)行程序時(shí)再用,合適方式是用二進(jìn)制流,直接將內(nèi)部數(shù)據(jù)保存到文件里。直接輸入輸出函數(shù):size_tfread(void*p,size_tsize,size_tnum,FILE*s)size_tfwrite(constvoid*p,size_tsize,size_tnum,FILE*s)fwrite向s輸出num個(gè)大小為size的數(shù)組元素,p指定數(shù)據(jù)的起始位置,各數(shù)據(jù)項(xiàng)順序?qū)懭胫付ㄎ募?。fread由s讀num個(gè)大小size的元素。p應(yīng)指數(shù)組,數(shù)組元素類型應(yīng)與size一致,數(shù)組大小至少為num。26直接存入文件后以同樣方式讀回,得到的數(shù)據(jù)不變。fwrite返回輸出的元素個(gè)數(shù),小于num說(shuō)明出錯(cuò)fread返回實(shí)際讀入元素的個(gè)數(shù)對(duì)二進(jìn)制流,應(yīng)該用feof檢查是否遇到文件結(jié)束27直接輸入輸出的例:設(shè)datatable是所用數(shù)組類型:
enum{TLEN=100};typedefdoubledatatable[TLEN];datatablem,n;設(shè)計(jì)算出的值存在m,要存入文件。設(shè)二進(jìn)制輸出流為msave。保存m的全部信息:fwrite(m,sizeof(double),TLEN,
msave);如果需要把以前保存的數(shù)據(jù)裝入數(shù)組n(數(shù)據(jù)的形式符合要求)。已為此建立了流msaved。下面調(diào)用完成輸入并把函數(shù)返回值存入變量num:num=fread(n,sizeof(double),TLEN,msaved);
288.3標(biāo)準(zhǔn)輸入輸出與格式控制標(biāo)準(zhǔn)IO的行式輸入輸出對(duì)標(biāo)準(zhǔn)輸入/輸出流也有行式IO函數(shù)。原型:char*gets(char*s)intputs(constchar*s)gets讀一行到s,用'\0'代行尾'\n'并返回s。s應(yīng)是字符數(shù)組。出錯(cuò)或遇文件結(jié)束返回NULLputs將字符串s以及一個(gè)換行符輸出。正常完成返回非負(fù)值,出錯(cuò)返回EOF用gets時(shí)應(yīng)注意數(shù)組越界(無(wú)法限制寫入長(zhǎng)度),應(yīng)選用足夠大的數(shù)組29一般使用形式:chars[256];...if(gets(s)!=NULL)......if(puts(s)!=EOF)...應(yīng)檢查和處理操作未正常完成的情況。gets函數(shù)無(wú)長(zhǎng)度控制,成為許多系統(tǒng)的安全漏洞。建議用fgets(buf,len,stdin)或者scanf(格式串里寫%ns,其中的n為長(zhǎng)度限制)代替gets30輸入格式控制以scanf為例介紹標(biāo)準(zhǔn)輸入函數(shù)的格式控制scanf的原型:intscanf(constchar*fmt,...);scanf將輸入流看成空白字符分隔的字段,讀入過(guò)程就是對(duì)這些字段的順序處理fmt指揮scanf進(jìn)行轉(zhuǎn)換,成功轉(zhuǎn)換得到的值賦給對(duì)應(yīng)變量(地址來(lái)自參數(shù))scanf處理完格式串或遇轉(zhuǎn)換失敗時(shí)結(jié)束,返回所完成的轉(zhuǎn)換項(xiàng)數(shù)31fmt里各種字符的意義與作用:空白字符(空格/制表符):要求scanf跳過(guò)輸入中遇到的空白字符(空格、換行符、制表符)普通字符:非轉(zhuǎn)換描述的非空白字符。要求scanf將它與輸入流下一個(gè)非空白字符匹配,字符相同時(shí)匹配成功,否則轉(zhuǎn)換失敗轉(zhuǎn)換描述:一個(gè)轉(zhuǎn)換描述刻畫對(duì)流中下一字段的轉(zhuǎn)換方式。以字符%開始,到轉(zhuǎn)換字符結(jié)束32轉(zhuǎn)換描述:%之后可有:*表示只匹配不賦值;長(zhǎng)度描述(整數(shù))指定輸入字符個(gè)數(shù);賦值目標(biāo)長(zhǎng)度指示h、l或L;最后是轉(zhuǎn)換字符。轉(zhuǎn)換順利完成時(shí)結(jié)果賦給參數(shù)所指變量(無(wú)*時(shí))。若有長(zhǎng)度描述就以指定個(gè)數(shù)的字符為字段。有星號(hào)(如%*s、%*6d等)時(shí)所匹配的東西不賦值,直接丟掉。轉(zhuǎn)換字符的意義,所要求實(shí)際輸入,對(duì)應(yīng)參數(shù)類型:d 十進(jìn)制形式的整數(shù)。 (int*)i 整數(shù),可為十、八或十六進(jìn)制表示。 (int*)o 八進(jìn)制整數(shù),可無(wú)先導(dǎo)字符0。 (int*)u 無(wú)符號(hào)十進(jìn)制整數(shù)。 (unsigned*)x 十六進(jìn)制整數(shù),可無(wú)先導(dǎo)0x或0X。 (int*)33c 字符,指定輸入寬度可輸入多字符到字符數(shù)組。不跳過(guò)空白,讀入多字符后不加'\0'。 (char*)s 非空白字符序列,可有長(zhǎng)度限制。在字符數(shù)組最后附加'\0'(做成字符串)。 (char*)e,f,g
符合C語(yǔ)言規(guī)定形式的浮點(diǎn)數(shù)。 (float*)p 指針值,形式與printf("%p")輸出一致。用于把由printf輸出的指針值讀回。 (void*)n 向?qū)?yīng)參數(shù)中寫入本次函數(shù)調(diào)用執(zhí)行到此已讀的字符個(gè)數(shù)。不實(shí)際讀入也不計(jì)轉(zhuǎn)換項(xiàng)數(shù)。 (int*)[...]
與所列字符的最長(zhǎng)序列匹配,寫入數(shù)組并附'\0'。用[]...]表示匹配串可含']'。 (char*)[^...]
與不含所列字符的最長(zhǎng)序列匹配,寫入數(shù)組并附'\0'。[^]...]表示不含']'。 (char*)% 與輸入流中的字符%匹配,不賦值。34轉(zhuǎn)換字符d、i、o、u、x前面可以標(biāo)明目標(biāo)長(zhǎng)度,h表示賦值目標(biāo)為short;l表示賦值目標(biāo)為long轉(zhuǎn)換字符e、f、g前加l表示目標(biāo)是double,L表示是longdouble加了這些字符,scanf將按指定類型構(gòu)造和賦值未做轉(zhuǎn)換前出錯(cuò)或者遇到文件結(jié)束時(shí)返回EOF其他情況下返回執(zhí)行中完成轉(zhuǎn)換的項(xiàng)數(shù),返回0表示第一個(gè)轉(zhuǎn)換失敗35例:設(shè)scanf當(dāng)時(shí)要處理轉(zhuǎn)換描述串%ld:scanf讀入并丟掉空白符號(hào)(可無(wú)),然后做匹配若遇到的非空白字符不能看作數(shù),則匹配失敗否則就逐個(gè)讀入字符,直至遇到第一個(gè)非數(shù)字字符將讀入的正負(fù)號(hào)及數(shù)字字符序列做成一個(gè)長(zhǎng)整數(shù),賦給指定的變量從這個(gè)轉(zhuǎn)換描述串之后繼續(xù)處理格式串如果轉(zhuǎn)換失敗,引起失敗的字符仍在流中,下次調(diào)用輸入函數(shù)將先讀到這個(gè)字符36寫好輸入需要考慮許多細(xì)節(jié),較麻煩。原因:輸入描述與外部打交道的方式,應(yīng)根據(jù)外部提供的信息決定工作方式。外部情況不受寫程序的人控制。寫好處理輸入的程序片段,需要考慮外部的各種可能,適當(dāng)處理有關(guān)情況(難說(shuō)“正確”,只能說(shuō)“適當(dāng)”)外部輸入不滿足程序要求時(shí),應(yīng)提供一些“信息”寫輸入時(shí)總要做一些假設(shè),考慮一些問題。書上有一些例子和說(shuō)明37輸出格式控制以printf為例(其他格式化輸出函數(shù)同)原型:intprintf(constchar*fmt,...);fmt里的非轉(zhuǎn)換描述直接輸出根據(jù)轉(zhuǎn)換描述順序轉(zhuǎn)換各實(shí)參,結(jié)果插入在fmt里相應(yīng)位置,形成整個(gè)輸出出錯(cuò)時(shí)返回負(fù)值正常完成返回實(shí)際輸出的字符個(gè)數(shù)38轉(zhuǎn)換描述從%開始到轉(zhuǎn)換字符止,中間可有若干字符,順序地可以有如下成分(都可缺):1)標(biāo)志字符:下面字符可以以任意順序出現(xiàn):-轉(zhuǎn)換結(jié)果在字段范圍內(nèi)左對(duì)齊+數(shù)值前面總輸出正負(fù)號(hào) 空格 轉(zhuǎn)換得到的首字符不是正負(fù)號(hào)時(shí)輸出一個(gè)空格0若數(shù)值輸出不能填滿字段,前面全填0#指定另一種形式。對(duì)轉(zhuǎn)換符o的數(shù)值前加0;x和X的非0結(jié)果前加0x或0X;e、E、f、g、G輸出時(shí)總寫小數(shù)點(diǎn);g和G,不去掉最后的0。392)一整數(shù)。最小寬度,轉(zhuǎn)換結(jié)果至少占這么寬,可更寬。若得到的序列不夠,在左邊(或右邊,有+時(shí))填空格。數(shù)值在有0標(biāo)志時(shí)在數(shù)字序列左邊填0。3)圓點(diǎn)及另一數(shù)。對(duì)字符串參數(shù)表示最大輸出字符數(shù);對(duì)e、E、f表示小數(shù)點(diǎn)后數(shù)位;對(duì)g、G表示有效數(shù)位;對(duì)整數(shù)表示最小輸出數(shù)字個(gè)數(shù),不夠時(shí)左邊添0。4)目標(biāo)長(zhǎng)度字符h、l或L。h和l用于整參數(shù),h指short或unsignedshort;l指long或unsignedlong。L指longdouble。字段寬度/精度可寫*,表示值由參數(shù)取得。提供值的參數(shù)必須是int。40轉(zhuǎn)換字符,所要求參數(shù)類型和實(shí)際輸出形式:d,i 帶符號(hào)的十進(jìn)制形式整數(shù)(int)o 無(wú)符號(hào)八進(jìn)制表示的整數(shù),無(wú)先導(dǎo)0(int)x,X 無(wú)符號(hào)十六進(jìn)制整數(shù),無(wú)先導(dǎo)0x或0X。用x時(shí)十以上數(shù)字用abcdef;對(duì)X用ABCDEF(int)u 無(wú)符號(hào)十進(jìn)制整數(shù)(int)c 字符,轉(zhuǎn)為unsignedchar輸出(int)s 字符序列,從參數(shù)所指位置直到字符'\0',或者達(dá)到字段的指定寬度為止(char*)f 一般實(shí)數(shù)形式[-]mmm.ddd,小數(shù)點(diǎn)后位數(shù)由精度描述定,默認(rèn)6。精度為0不輸出小數(shù)點(diǎn)(double)41e,E 科學(xué)記數(shù)法[-]m.dde±xx或[-]m.ddE±xx,小數(shù)點(diǎn)后位數(shù)由精度描述確定,默認(rèn)6。精度為0時(shí)不輸出小數(shù)點(diǎn)(double)g,G 靈活形式。指數(shù)小于-4或大于等于精度描述時(shí)用%e或%E形式輸出,否則用%f形式輸出。末尾的0或小數(shù)點(diǎn)不輸出(double)p 指針,用具體實(shí)現(xiàn)確定的形式(void*)n 把本次函數(shù)執(zhí)行到此已輸出的字符數(shù)寫進(jìn)參數(shù)。處理這個(gè)“轉(zhuǎn)換描述”進(jìn)行不進(jìn)行任何轉(zhuǎn)換(int*)% 輸出字符%,無(wú)轉(zhuǎn)換42通過(guò)字段寬度和精度控制、對(duì)齊等,靈活運(yùn)用轉(zhuǎn)換描述可形成所需輸出形式。幾個(gè)實(shí)例:%16.8lf%-10.6f%20.12e%010ld%.7s格式串里可用星號(hào)表示字段寬度和精度,實(shí)際寬度精度由參數(shù)取得。這個(gè)功能使我們可以在程序里通過(guò)程序機(jī)制控制輸出格式。例:printf("%s%*d\n",”Num:",width,num);先輸出一個(gè)字符串,然后輸出num的值(假定num是整型變量),字段寬度由(int變量)width值確定。43字符串作為格式化IO的對(duì)象文件是字節(jié)序列,正文流是字符序列,從文本流輸入就是從中讀取一段。輸出的情況相反。字符串也是字符序列,可作為IO對(duì)象標(biāo)準(zhǔn)庫(kù)有兩個(gè)以字符串為對(duì)象的格式化IO函數(shù)。輸入函數(shù)從字符串讀并轉(zhuǎn)換,結(jié)果賦給指定變量。輸出函數(shù)實(shí)現(xiàn)相反過(guò)程,把輸出存入字符數(shù)組并做成字符串函數(shù)原型是:intsscanf(char*s,constchar*fmt,...)intsprintf(char*s,constchar*fmt,...)與對(duì)應(yīng)格式化IO函數(shù)相同,只是對(duì)象是字符串44出錯(cuò)處理輸出出錯(cuò)信息是希望顯示到屏幕供人讀。通過(guò)stdout不合適:輸出定向到文件也使出錯(cuò)信息送到文件。送到標(biāo)準(zhǔn)錯(cuò)誤流stderr的信息不受定向影響。改造前面程序cat,只需要改動(dòng)一個(gè)語(yǔ)句:fprintf(stderr,"%s,can'topeninfile:%s\n",name,*argv);文件錯(cuò)誤檢查:intferror(FILE*stream)IO出錯(cuò)時(shí)設(shè)置相關(guān)流的出錯(cuò)標(biāo)志變量。ferror檢查流的出錯(cuò)標(biāo)志。當(dāng)stream的狀態(tài)變量設(shè)置時(shí)返回非0。錯(cuò)誤標(biāo)志復(fù)位(清除)函數(shù)
voidclearerr(FILE*stream)45標(biāo)準(zhǔn)庫(kù)錯(cuò)誤處理:為檢查程序執(zhí)行中出錯(cuò),庫(kù)提供了一些機(jī)制。每個(gè)C系統(tǒng)定義了一組錯(cuò)誤編號(hào),0表示無(wú)錯(cuò),其余值表示各種錯(cuò)誤。一些函數(shù)出錯(cuò)時(shí)自動(dòng)給狀態(tài)變量errno設(shè)錯(cuò)誤編號(hào),還定義了相應(yīng)的信息串。見<errno.h>。打印當(dāng)時(shí)錯(cuò)誤信息:voidperror(char*s)檢查當(dāng)時(shí)錯(cuò)誤編號(hào)(perror調(diào)用之前的最近錯(cuò)誤),把對(duì)應(yīng)信息串送到stderr。輸出形式: 字符串s
冒號(hào)錯(cuò)誤信息串換行46例:設(shè)有一組文件,每個(gè)文件存一批實(shí)數(shù)。寫程序由用戶取得文件名,對(duì)各文件中的數(shù)值求平均值輸出。8.4程序?qū)嵗绦蚬δ芊纸猓簭奈募x數(shù)值求平均值并輸出是一項(xiàng)獨(dú)立工作,定義為函數(shù),原型設(shè)計(jì)為:voidaverage(FILE*fp,char*fname);它要求的參數(shù)一個(gè)打開的輸入文件指針和文件名。由主函數(shù)處理取得文件名并打開文件的工作。綜合上面考慮,average可定義為:47voidaverage(FILE*fp,char*fname){doublex,sum=0.0;
intl=0,n=0,m,c;printf("\nFile%s:\n",fname);whlie((m=fscanf(fp,"%lf",&x))!=EOF){++l;if(m==1){sum+=x;n++;continue;}
printf("Error,line%d:",l);while(!isspace(c=getc(fp)))
fputc(c,stderr);/*丟掉數(shù)據(jù)并通知用戶*/
fputc('\n',stderr);}
printf("Average:%16.8f\n",sum/n);}48主函數(shù)確定循環(huán)終止方法。下面用文件結(jié)束符,給文件結(jié)束信號(hào)(組合鍵Ctrl-Z)程序結(jié)束:intmain(void){
charname[128];FILE*fp;while(1){printf("Filename(Ctrl-Ztoend):");if(scanf("%127s",name)==EOF)break;
if((fp=fopen(name,"r"))==NULL)printf("Can'topen:%s\n",name);
else{
average(fp,name);fclose(fp);
}}
printf("Bye!\n");return0;}49主函數(shù)的另一版本,要求用戶通過(guò)命令行參數(shù)提供文件名。命令行沒有文件名就什么也不做。intmain(intargc,char**argv){FILE*fp;while(*++argv!=NULL){if((fp=fopen(*argv,"r"))==NULL)printf("Can'topen:%s\n",*argv);
else{
average(fp,*argv);fclose(fp);}}printf("Bye!\n");return0;}50例:考慮一個(gè)背英語(yǔ)單詞程序,基本循環(huán)是顯示一個(gè)中文詞,要求用戶輸入對(duì)應(yīng)的英文單詞并給以評(píng)判。
程序運(yùn)行中應(yīng)保存一對(duì)對(duì)中文/英文詞。最好將單詞存在文件里,啟動(dòng)程序后將單詞裝入。需要用文件IO。
為簡(jiǎn)化輸入,應(yīng)該先設(shè)計(jì)好單詞文件的格式。例如每行里放一對(duì)英文詞和中文詞,英文在前中文在后,空格分隔。(文件格式設(shè)計(jì)很重要)單詞文件可能不止一個(gè),用戶通過(guò)交互提供文件名,要求程序裝入文件內(nèi)容,而后交互練習(xí)。中文和英文詞用字符串形式存入一個(gè)兩維字符數(shù)組。
51可以有下面定義:/*WDNUM:中英文詞數(shù);WDLEN:單詞存儲(chǔ)數(shù)組長(zhǎng)度,ROUND:一輪練習(xí)的次數(shù)*/enum{WDNUM=1000,WDLEN=32,ROUND=20};charwds[WDNUM*2][WDLEN];#defineENGLISH(i)wds[2*(i)]#defineCHINESE(i)wds[2*(i)+1]定義宏是為寫程序方便。已經(jīng)可以定義main:52intmain(void){charfn[256];FILE*fp;intterms;do{getnstr("Wordfilename:",256,fn);if((fp=fopen(fn,"r"))==NULL)printf("Wrongfilename.");else{terms=readfile(fp,WDNUM,wds);
fclose(fp);if(terms==0)continue;wordgame(terms,wds,ROUND);}}while(next("wordfile"));return0;}53getnstr從標(biāo)準(zhǔn)輸入讀一段字符,遇空白字符結(jié)束:voidgetnstr(charprompt[],intlim,charbf[]){
intc,i=0;printf("%s",prompt);while(i<lim-1&&(c=getchar())!=EOF
&&!isspace(c))bf[i++]=c;if(c!='\n')while(getchar()!='\n');/*吃掉本行剩余字符*/
bf[i]='\0';}本函數(shù)認(rèn)為輸入行里有用信息就是一個(gè)字段(由空白界定),其他信息都應(yīng)拋棄。讀入的字符存入數(shù)組bf,做成字符串形式。注意檢查越界問題。
54next是前面簡(jiǎn)單函數(shù)的推廣,它輸出提示串參數(shù),通過(guò)讀入的y或者n確定返回真假值。本函數(shù)只在遇到y(tǒng)時(shí)返回1,其余情況都返回0:intnext(chars[]){intc;printf("Next%s?(y/n):",s);
do{c=getchar();
}while(isspace(c));/*讀到一個(gè)非空白字符*/
while(getchar()!='\n')
;/*吃掉本行剩余字符*/
if(c=='y'||c=='Y')return1;elsereturn0;}這兩個(gè)函數(shù)都可能用到許多程序里。55wordgame采用隨機(jī)選擇策略(有許多改造可能):voidwordgame(intterms,intrd,charwds[][WDLEN]){
intn,i;charwd[WDLEN];do{for(i=0;i<rd;++i){n=rand()%terms;printf("%s",CHINESE(n));getnstr(">",wd,WDLEN);if(strcmp(wd,ENGLISH(n))==0)printf("Ok!\n");elseprintf("Wrong!Itis:%s\n",ENGLISH(n));}}while(next("Round?"));}56readfile采用按行輸入方式,讀入一行后分析輸入并復(fù)制到指定數(shù)組,以便必要時(shí)生成錯(cuò)誤信息:intreadfile(FILE*fp,
intlim,charwds[][WDLEN]){charline[256],*p;intl=0,n=0;while(n<lim&&fgets(line,256,fp)!=NULL){++l;p=line;p=charscopy(WDLEN-1,ENGLISH(n),p,'');p=charscopy(WDLEN-1,CHINESE(n),p,'');if(*ENGLISH(n)=='\0'||*CHINESE(n)=='\0')printf("Wrongline#%d:%s",l,line);else++n;}returnn;}57charscopy把由s開始不超過(guò)lim個(gè)非空白字符復(fù)制到單詞數(shù)組t。delim表示單詞分隔符,前面用''。也支持用其他分隔符,這種設(shè)計(jì)使函數(shù)更通用。
char*charscopy(intlim,chart[],chars[],chardelim){inti;while(isspace(*s))++s;/*跳過(guò)s中的空白*/for(i
溫馨提示
- 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ì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 西京學(xué)院《室內(nèi)陳設(shè)設(shè)計(jì)》2022-2023學(xué)年第一學(xué)期期末試卷
- 音樂萬(wàn)馬奔騰課件
- 西京學(xué)院《版面設(shè)計(jì)》2023-2024學(xué)年第一學(xué)期期末試卷
- 西華師范大學(xué)《小學(xué)語(yǔ)文課程與教學(xué)》2022-2023學(xué)年第一學(xué)期期末試卷
- 西華師范大學(xué)《水污染防治技術(shù)》2023-2024學(xué)年第一學(xué)期期末試卷
- 西華師范大學(xué)《攝影與攝像技藝》2021-2022學(xué)年第一學(xué)期期末試卷
- 9正確認(rèn)識(shí)廣告 說(shuō)課稿-2024-2025學(xué)年道德與法治四年級(jí)上冊(cè)統(tǒng)編版
- 電工高級(jí)工專項(xiàng)測(cè)試題及答案
- 第十二章第二節(jié)《滑輪》說(shuō)課稿 -2023-2024學(xué)年人教版八年級(jí)物理下冊(cè)
- 2024年代森錳鋅行業(yè)前景分析:代森錳鋅行業(yè)發(fā)展趨勢(shì)推動(dòng)行業(yè)國(guó)際化
- 急性嚴(yán)重創(chuàng)傷搶救流程圖
- 家長(zhǎng)進(jìn)課堂小學(xué)生建筑知識(shí)課件
- 人身保險(xiǎn)合同糾紛原告方代理詞(參考范本)
- 鐵路安全生產(chǎn)管理問題及措施
- 2023年口腔醫(yī)學(xué)期末復(fù)習(xí)-牙周病學(xué)(口腔醫(yī)學(xué))考試歷年真題集錦帶答案
- 函數(shù)的概念 省賽獲獎(jiǎng)
- 網(wǎng)絡(luò)安全培訓(xùn)-
- 地下車位轉(zhuǎn)讓協(xié)議
- 大學(xué)生創(chuàng)新創(chuàng)業(yè)教程PPT完整全套教學(xué)課件
- 2018年蜀都杯《辛亥革命》終稿z
- 電梯洞口水平防護(hù)方案
評(píng)論
0/150
提交評(píng)論