




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
第4章基本程序設(shè)計(jì)技術(shù)高級(jí)語言程序設(shè)計(jì)問同學(xué)們一些問題:通讀了教材嗎?通常教材應(yīng)該讀3遍:預(yù)習(xí)讀1遍,聽課時(shí)讀1遍,期末復(fù)習(xí)時(shí)再讀1遍。上課做了筆記嗎?雖然老師總是把重要知識(shí)點(diǎn)貼在QQ群里,但那也不是足夠的。重要的是學(xué)習(xí)者抓住課堂教學(xué)的重點(diǎn)和難點(diǎn),根據(jù)自己的實(shí)際情況做適量的筆記。(現(xiàn)在老師在QQ群里貼出重點(diǎn)和難點(diǎn),是為了引導(dǎo)同學(xué)們學(xué)會(huì)做筆記)是否閱讀了老師批閱后的源程序?有沒有耐心地理解老師的批閱意見?有沒有耐心地讀一遍其他同學(xué)的源程序?是否會(huì)避免其他同學(xué)所犯的錯(cuò)誤?有沒有足量完成老師布置的上機(jī)編程練習(xí)?雖然老師只收取部分程序,但自己應(yīng)該自覺地足量完成。2對(duì)勤奮好學(xué)的同學(xué)的寄語:努力學(xué)習(xí)總是能夠得到回報(bào)的。努力學(xué)習(xí)的成果應(yīng)該主動(dòng)地向老師展示。例如:如果你遵照老師的建議,做完了教材上所有的編程練習(xí)題,那么可以主動(dòng)地把所編寫的程序打包發(fā)送給老師,老師會(huì)欣然接受并做耐心的批閱,給你個(gè)人足夠多的指導(dǎo)和幫助。34從前面的編程工作中可以體會(huì)到,雖然寫程序時(shí)要處理許多瑣碎細(xì)節(jié),但這也是一件有趣的工作,是對(duì)人的智力挑戰(zhàn)。為了完成一個(gè)程序,首先要分析問題以尋找解決方案,為此需要聰明才智和想像力,各種相關(guān)領(lǐng)域的知識(shí)和技術(shù)都可能有用。要把設(shè)計(jì)變成現(xiàn)實(shí),變成可以運(yùn)行的程序,既需要發(fā)揮智力,又需要有條有理地工作,還要非常細(xì)心。一個(gè)小錯(cuò)誤就可以使程序無法編譯或不能正確執(zhí)行。當(dāng)然,高度精確性也是現(xiàn)代社會(huì)的需要,寫程序的過程能提供許多有益的體驗(yàn)。5學(xué)習(xí)程序設(shè)計(jì)需要注意規(guī)律性的東西。要注意前人的經(jīng)驗(yàn)。只有認(rèn)真學(xué)習(xí)怎樣寫好小程序,弄清其中的基本道理,才能做出大程序。三種流程模式的總結(jié):順序模式最簡單選擇模式:要確定判斷條件及不同情況下的動(dòng)作開始的難點(diǎn)在實(shí)現(xiàn)重復(fù)執(zhí)行的循環(huán)。重復(fù)執(zhí)行比較復(fù)雜,牽涉問題多,是本章重點(diǎn)本章還討論:常用標(biāo)準(zhǔn)庫函數(shù)和
交互式程序設(shè)計(jì)中的輸入處理6只有在程序設(shè)計(jì)實(shí)踐中才能學(xué)好程序設(shè)計(jì):1、模仿好的范例;2、自己動(dòng)手動(dòng)腦,反復(fù)實(shí)踐從問題出發(fā)做出程序的整個(gè)過程;3、多想想自己的程序做得怎么樣,能不能做得更好。7目
錄4.1循環(huán)程序設(shè)計(jì)4.2常用標(biāo)準(zhǔn)庫函數(shù)4.3交互式程序設(shè)計(jì)中的輸入處理4.4程序設(shè)計(jì)實(shí)例4.5程序動(dòng)態(tài)除錯(cuò)方法(二)84.1循環(huán)程序設(shè)計(jì)寫循環(huán)首先要發(fā)現(xiàn)循環(huán)。注意計(jì)算中的重復(fù)性動(dòng)作,引進(jìn)循環(huán)可能統(tǒng)一描述和處理。重復(fù)動(dòng)作的常見實(shí)例:一批類似數(shù)據(jù)做同樣加工處理累積一批可按規(guī)律算出的數(shù)據(jù)(累加等)反復(fù)從一個(gè)結(jié)果算出下一結(jié)果(遞推)若重復(fù)次數(shù)很多,就應(yīng)該考慮用循環(huán)如果重復(fù)次數(shù)無法確定,就必須用循環(huán)描述9從發(fā)現(xiàn)重復(fù)性動(dòng)作到寫好一個(gè)循環(huán)結(jié)構(gòu),還需考慮和解決許多具體問題:每次循環(huán)中需要做的處理工作;循環(huán)的控制……具體還包括使用語言里的哪種結(jié)構(gòu)來實(shí)現(xiàn)循環(huán)。本節(jié)將展示一批程序?qū)嵗?,介紹一些循環(huán)程序設(shè)計(jì)問題。先分析問題,逐漸發(fā)掘完成程序的線索,最終完成能解決問題的程序?!皬膯栴}到程序”10讀者需要理解:程序不是教條。即使對(duì)一個(gè)典型問題,也沒有需要死記硬背的標(biāo)準(zhǔn)解答。只要不是極端簡單的問題,總會(huì)有許多解決方法,可以寫出許多在形式或?qū)嵸|(zhì)上有差異的程序。正確的程序也常有優(yōu)劣之分。讀者需要學(xué)習(xí)寫出優(yōu)秀的程序。114.1循環(huán)程序設(shè)計(jì)4.1.1生成與檢查4.1.2浮點(diǎn)誤差4.1.3迭代和逼進(jìn)4.1.4通項(xiàng)計(jì)算4.1.5循環(huán)中的幾種變量12【例4-1】寫程序,打印輸出1到200之間的所有完全平方數(shù),即那些是另一個(gè)數(shù)的平方的數(shù)。通過分析可以發(fā)現(xiàn),這樣一個(gè)簡單問題也有許多不同解法。沒有直接判斷手段,需要寫一段程序填充4.1.1生成與檢查方法一:逐個(gè)檢查,遇平方數(shù)打印。重復(fù)做,每次檢查一個(gè)數(shù)。循環(huán)框架:for(n=1;n<=200;n++)if(n是完全平方數(shù))打印n;13可以順序檢查,是否存在某數(shù),其平方恰為n。這構(gòu)成(循環(huán)內(nèi)的)新循環(huán),需要一個(gè)新循環(huán)變量。k可以從1開始,遞增,直至k*k>n:
for(k=1;k*k<=n;k++) if(k*k==n)打印n;寫出主程序:intmain(){intn,k;for(n=1;n<=200;++n)for(k=1;k*k<=n;++k)if(k*k==n)//如果n是k的平方,即n是完全平方數(shù)
cout<<n<<"";cout<<endl;//最后換一行
return0;}for(n=1;n<=200;n++)if(n是完全平方數(shù))打印n;14方法二:需要打印的一定是從1開始連續(xù)幾個(gè)整數(shù)的平方,可從1開始打印到平方大于200為止。for(n=1;n*n<=200;++n)cout<<n*n<<"";/*注意打印什么*/方法三:還可以考慮利用遞推公式:15方法一的策略是:生成所有備選數(shù)據(jù)(1到200的整數(shù)),檢查挑選出合格的(排除不合格的)。
for(n=1;n<=200;++n)for(k=1;k*k<=n;++k)if(k*k==n)//如果n是k的平方
cout<<n<<"";編程策略中,“生成與檢查”是解決問題的常用方法。方法二和方法三是針對(duì)具體問題的特定方法。<--生成一批數(shù)據(jù)<--對(duì)每個(gè)數(shù)據(jù)進(jìn)行檢查,挑選出符合要求的數(shù)據(jù)16補(bǔ)充例題:如果一個(gè)三位數(shù)的各位數(shù)字的立方和等于該數(shù)本身,則稱該數(shù)為“水仙花數(shù)”。例如:153=13+53+33。請(qǐng)編程找出并打印所有的“水仙花數(shù)”。使用“生成與檢查”策略來解答:“生成”一批數(shù):做一個(gè)從100到999的循環(huán)根據(jù)題目要求對(duì)每個(gè)數(shù)進(jìn)行“檢查”:依次分解出每個(gè)數(shù)的百位、十位和個(gè)位數(shù)字,如果滿足條件則打印輸出。利用整數(shù)除法和取余。在希臘神話中,貌美青年那喀索斯(narcissus)愛上了自己在水中的倒影,他死后化作水仙花,此花即因之命名。所以水仙花數(shù)也稱為自戀數(shù)、冪數(shù),完整名稱為超完全數(shù)字不變數(shù)(pluperfectdigitalinvariant)。intmain(){ //打印輸出所有水仙花數(shù) inti,j,k,n; cout<<"水仙花數(shù):"; for(n=100;n<1000;n++){ i=n/100; //分解出百位 j=n/10%10;//分解出十位 k=n%10; //分解出個(gè)位 if(n==i*i*i+j*j*j+k*k*k) cout<<n<<endl; } return0;}17<--生成一批數(shù)據(jù)<--對(duì)每個(gè)數(shù)進(jìn)行檢查,找出符合要求的數(shù)一種錯(cuò)誤寫法如下:intmain(){ //打印輸出所有水仙花數(shù) inti,j,k,n; cout<<"水仙花數(shù):"; i=n/100; //分解出百位 j=n/10%10; //分解出十位 k=n%10; //分解出個(gè)位 for(n=100;n<1000;n++){ if(n==i*i*i+j*j*j+k*k*k) cout<<n<<endl; } return0;}18以數(shù)學(xué)函數(shù)關(guān)系來看待i,j,k與n的關(guān)系,以為i,j,k會(huì)自動(dòng)跟著n而變化。這是錯(cuò)誤的!計(jì)算機(jī)程序的本質(zhì),是按順序進(jìn)行計(jì)算。必須對(duì)每個(gè)n分別計(jì)算出i,j,k并判斷關(guān)系194.1.2浮點(diǎn)誤差計(jì)算機(jī)中用二進(jìn)制浮點(diǎn)數(shù)表示小數(shù),可能存在浮點(diǎn)誤差,即在計(jì)算機(jī)中所保存的小數(shù)與實(shí)際的十進(jìn)制小數(shù)之間有誤差。在通常情況下可能對(duì)計(jì)算結(jié)果影響不大,但是,在某些特定情況下卻對(duì)計(jì)算結(jié)果存在嚴(yán)重的影響。用一個(gè)含有利用循環(huán)語句進(jìn)行求和的例題說明?!纠?-2】假定有一只烏龜決心去做環(huán)球旅行。出發(fā)時(shí)它躊躇滿志,第一秒四腳飛奔,爬了1米。隨著體力和毅力的下降,它第二秒鐘爬了1/2米,第三秒鐘爬了1/3米,第四秒鐘爬了1/4米,如此等等。問這只烏龜一小時(shí)能爬出多遠(yuǎn)?爬出20米需要多少時(shí)間?20顯然,題目中要計(jì)算的是無窮級(jí)數(shù)和式前面的有限一段之和。由高等數(shù)學(xué)可知,。也就是說,只要烏龜堅(jiān)持爬下去,它不但能完成環(huán)球旅行,也能爬到宇宙的盡頭。在題目中有兩問,即分別要求出給定n的求和上限值時(shí)這個(gè)級(jí)數(shù)和式的值是多少,以及
n的值為多大時(shí)該級(jí)數(shù)和式能達(dá)到給定的值。用這個(gè)例子研究一下浮點(diǎn)數(shù)的誤差問題,并對(duì)用于保存累加求和值的變量分別設(shè)為double
和float
類型的情況做些比較。21intmain(){intm,n;doublex,dist;//計(jì)算烏龜m秒爬出的距離
cout<<"請(qǐng)輸入烏龜爬行時(shí)間(以秒為單位):";cin>>m;cout<<"m="<<m<<endl;dist=0.0;for(n=1;n<=m;++n){dist+=1.0/n;//注意不能寫成1/nif(n%100000==0)//按一定的間隔輸出中間值cout<<"n="<<n<<"dist="<<dist<<endl;}n--;//循環(huán)結(jié)束時(shí),n的值為m+1,比實(shí)際所用值多1,所以要減1。
cout<<"烏龜在"<<n<<"秒鐘之后爬行了"<<dist<<"米遠(yuǎn)。"<<endl;22//計(jì)算烏龜爬行dist米距離所需的時(shí)間
cout<<"\n請(qǐng)輸入待爬行的距離(以米為單位,例如20):";cin>>dist;x=0.0;for(n=1;x<dist;++n){x+=1.0/n;if(n%100000==0)cout<<"n="<<n<<"x="<<setprecision(10)<<x<<endl;}cout<<"烏龜爬行"<<dist<<"米需要"<<--n<<"秒鐘。"<<endl;cout<<"約為"<<n/3600<<"小時(shí),"<<n/3600/24<<"天。"<<endl;return0;}教師測試練習(xí)由x提供循環(huán)條件
(而非由n指定循環(huán)次數(shù))每100000次才輸出一次中間量23測試運(yùn)行時(shí),先輸入一個(gè)時(shí)間(例如3600秒),程序會(huì)很快計(jì)算出: 烏龜在3600秒鐘之后爬行了8.76604米遠(yuǎn)。然后試著輸入一個(gè)較短的距離(例如20米),程序會(huì)花費(fèi)一段時(shí)間之后計(jì)算出: 烏龜爬行20.0000000000米需要272400600秒鐘。 約為75666小時(shí),3152天。這是很合理的計(jì)算結(jié)果。24輸入一個(gè)更大的時(shí)間和更長的距離,會(huì)怎么樣?顯然,輸入時(shí)間長度的時(shí)候,由于m是int類型,所以最大值只能是INT_MAX,最終所計(jì)算得的距離還是一個(gè)合理的值。如果輸入一個(gè)更長的距離(例如23),那么循環(huán)變量n就會(huì)溢出(出現(xiàn)負(fù)數(shù)!),結(jié)果沒有意義。計(jì)算機(jī)確實(shí)是一種數(shù)值范圍有限的機(jī)器,它只能在有限的范圍內(nèi)進(jìn)行工作。25把程序中的變量x和dist的類型改為float,運(yùn)行時(shí)會(huì)怎么樣呢?結(jié)果是,大約在2100000秒之后,爬行距離最大達(dá)到15.40368271時(shí)就不再增長了。也就是意味著,當(dāng)n大于2100000時(shí),對(duì)x的計(jì)算在10位精度下已經(jīng)產(chǎn)生了明顯的誤差。
x+=1.0/n;如果把變量x和dist的類型改為longdouble類型,又會(huì)如何?
……
doublex,dist;
floatx,dist;26對(duì)浮點(diǎn)數(shù)類型的使用建議:float的表示范圍和精度不能滿足許多常規(guī)計(jì)算的需要;浮點(diǎn)計(jì)算通常都應(yīng)該用double類型;longdouble類型可能會(huì)影響程序效率,而且受到具體編譯器的限制。特殊情況中浮點(diǎn)誤差積累可能更迅速。兩個(gè)重要情況:1)將一批小的數(shù)加到很大的數(shù)上,會(huì)導(dǎo)致丟掉小的數(shù)的重要部分,甚至小數(shù)整個(gè)被丟掉(例中情況)2)兩個(gè)值接近的數(shù)相減,可能導(dǎo)致精度大大下降274.1.3迭代和逼近【例4-3】求x立方根的迭代公式(遞推公式)是:
從鍵盤上輸入x值,然后利用這個(gè)公式求x的立方根的近似值,要求達(dá)到精度。無法確定循環(huán)次數(shù),只能用循環(huán)。只能按題目給出循環(huán)條件(計(jì)算方法的研究結(jié)果)求新迭代值要用到x。判斷終止需要先后兩個(gè)近似值,必須用兩個(gè)變量,這可看作是兩個(gè)合作的迭代變量。x1,x2,x3,x4,x5,x6,x7,...xn,xn+1,...28intmain(){doublex,x1,x2;cout<<"inputx:";cin>>x;
x1=x;
x2=(2.0*x1+x/(x1*x1))/3.0;while(fabs((x2-x1)/x1)>=1E-6){
x1=x2;
x2=(2.0*x1+x/(x1*x1))/3.0;cout<<x2<<endl;}cout<<"cubicrootofxis:"<<x2<<endl;return0;}改用do…while可減少重復(fù)語句
x2=x;do{x1=x2;x2=(2.0*x1+x/(x1*x1))/3.0;cout<<x2<<endl;}while(fabs((x2-x1)/x1)>=1E-6);注意x1與x2的迭代變化!精度不滿足要求時(shí)執(zhí)行循環(huán),滿足要求時(shí)結(jié)束29多次運(yùn)行,每次運(yùn)行時(shí)輸入不同的數(shù)據(jù)進(jìn)行測試它??梢园l(fā)現(xiàn),在輸入27、-1000、3、-1這樣的數(shù)據(jù)時(shí)都能給出正確結(jié)果,但是在輸入0
時(shí)會(huì)得到輸出結(jié)果為nan。intmain(){doublex,x1,x2;cout<<"Pleaseinputx:";cin>>x;x2=x;if(x==0){cout<<"cubicrootof"<<x<<"is:"<<x2;return0;//程序結(jié)束,返回值為0}……添加對(duì)0的額外處理30這個(gè)程序也很典型。人們研究了許多典型函數(shù)的計(jì)算方法,許多函數(shù)的計(jì)算都采用類似本函數(shù)計(jì)算方式的公式,其中需要通過一系列迭代計(jì)算,取得一系列逐漸逼進(jìn)實(shí)際函數(shù)值的近似值。實(shí)現(xiàn)這類計(jì)算的程序通常都具有上述函數(shù)的形式:采用幾個(gè)互相協(xié)作的臨時(shí)性變量,通過它們值的相互配合,最終算出所需要的函數(shù)值?!纠?-4】Fibonacci(斐波納契)數(shù)列:1,1,2,3,5,8,13,21,34,55,89,144,233,……
遞推定義為:F1=1,F2=1,……Fn=Fn?1+Fn?2(n>2)請(qǐng)寫程序,對(duì)于從鍵盤輸入的介于3到46之間的正整數(shù)n,利用上述公式求出Fn。31程序中需要檢查輸入的n值是否介于[3,46]。利用遞推公式求Fn:從F1和F2出發(fā),向前逐個(gè)推算,直至算出所需的Fn為止。每次由前兩項(xiàng)算出后一項(xiàng),所以需要兩個(gè)變量保存相鄰兩項(xiàng),使之在每個(gè)k>=2時(shí)總對(duì)應(yīng)著Fk?1、Fk
。用一個(gè)臨時(shí)變量中轉(zhuǎn),在k取n時(shí)得到Fn-1和
Fn。intmain(){intn;do{cout<<"Pleaseinputn(between3and46):";cin>>n;}while(n<3||n>46);
inta=1,b=1;//前后相鄰的兩項(xiàng),初始化為第1、2項(xiàng);
inttmp;
//臨時(shí)(temporary)變量
cout<<a<<"\t"<<b<<"\t";intk=2;while(k<n){tmp=b;//暫存b=b+a;//遞推a=tmp;//跟進(jìn)++k;cout<<b<<(k%5==0?"\n":"\t");}cout<<"\nThe"<<n<<"thFibonaccinumberis"<<b<<endl;return0;}32334.1.4通項(xiàng)計(jì)算【例4-5】從鍵盤上輸入一個(gè)x值,然后利用公式求出sinx的近似值(單項(xiàng)絕對(duì)誤差小于1E-6),并與標(biāo)準(zhǔn)庫中的sin函數(shù)的計(jì)算結(jié)果進(jìn)行比較。方法:循環(huán)累加,n趨向無窮的過程中項(xiàng)值趨于0,而累加值趨向函數(shù)值。需要用循環(huán)。保存累加和的變量sum,循環(huán)中求得項(xiàng)值用t保存。34sum=0.0;對(duì)n為0計(jì)算t;while(需要繼續(xù)){sum=sum+t;
計(jì)算下一個(gè)t;}循環(huán)結(jié)束條件:新項(xiàng)絕對(duì)值小于10–6for(t=x,i=1;i<=n;++i)t*=-(x*x/(2*i)/(2*i+1);有很多重復(fù)計(jì)算t=-t*x*x/(2*n)/(2*n+1);找出前后項(xiàng)之間的關(guān)系:減少了重復(fù)計(jì)算35intmain(){ doublex,sum,t; cout<<"Pleaseinputx:"; cin>>x; sum=0.0; t=x; intn=0; while(t>=1E-6||t<=-1E-6){ sum=sum+t; n=n+1; t=-t*x*x/(2*n)/(2*n+1); cout<<"n="<<n<<"t="<<t<<"sum="<<sum<<endl; } cout<<"mysin"<<x<<"is:"<<sum<<endl; cout<<"standardsin"<<x<<"is:"<<sin(x); return0;}多次運(yùn)行,每次輸入不同的參數(shù)值進(jìn)行測試:2,5,10,20,50,100,1000可以發(fā)現(xiàn)結(jié)果與x值有關(guān)。絕對(duì)值很大時(shí)耗時(shí)較長,誤差很大。36intmain(){ doublex,sum,t; cout<<"Pleaseinputx:"; cin>>x; sum=0.0; t=x; intn=0; while(t>=1E-6||t<=-1E-6){ sum=sum+t; n=n+1; t=-t*x*x/(2*n)/(2*n+1); cout<<"n="<<n<<"t="<<t<<"sum="<<sum<<endl; } cout<<"mysin"<<x<<"is:"<<sum<<endl; cout<<"standardsin"<<x<<"is:"<<sin(x); return0;}x=fmod(x,2*3.14159265);改進(jìn):37啟示:1、理解問題非常重要。發(fā)現(xiàn)了項(xiàng)的遞推性質(zhì)能節(jié)省許多計(jì)算(否則就要再寫一個(gè)嵌套循環(huán)完成項(xiàng)的計(jì)算)。2、級(jí)數(shù)收斂性質(zhì)能幫人認(rèn)識(shí)情況,改進(jìn)計(jì)算方法??傊瑢懗绦驎r(shí)必須仔細(xì)考慮問題本身的性質(zhì)。38課堂筆記4.1.1生成和檢查:同一個(gè)問題有多種解法;常用“生成和檢查”;還有一些針對(duì)具體問題的具體解法。4.1.2浮點(diǎn)誤差(1)浮點(diǎn)數(shù)通常都用double類型;極少用float和longdouble。(2)循環(huán)時(shí)部分地輸出中間量。4.1.3迭代和逼進(jìn):注意變量的迭代變化;合理地選擇循環(huán)結(jié)構(gòu)(while,do…while或for);選用典型的參數(shù)進(jìn)行測試,完善程序。4.1.4通項(xiàng)計(jì)算:寫循環(huán)時(shí)需要找出前后項(xiàng)之間的關(guān)系,以減少計(jì)算量;選用典型參數(shù)測試,完善程序。394.1.5循環(huán)中的幾種變量循環(huán)中常出現(xiàn)幾類變量,注意這些有助于對(duì)循環(huán)的思考和分析。也是寫循環(huán)程序的經(jīng)驗(yàn)總結(jié)。注意:分類不是絕對(duì)的,不同類別沒有截然界限。1)循環(huán)控制變量(循環(huán)變量):循環(huán)前設(shè)初值,循環(huán)中遞增/遞減,達(dá)到/超過界限時(shí)循環(huán)結(jié)束。它們控制循環(huán)的進(jìn)行/結(jié)束。for中常有這類變量。for(n=0;n<10;++n)......for(n=30;n>=0;--n)......for(n=2;n<52;n+=4)......這種循環(huán)是固定次數(shù)的循環(huán)。這種循環(huán)可能展開。在循環(huán)體內(nèi)不要修改循環(huán)變量402)累積變量:循環(huán)中常用+=或*=等更新。初值通常用運(yùn)算的單位元(累加的初值為0;累乘的初值為1為初值)。循環(huán)結(jié)束時(shí)變量終值被作為循環(huán)計(jì)算結(jié)果。3)遞推變量:前兩類變量的推廣。幾個(gè)協(xié)同工作的變量,每次由幾個(gè)變量推出一個(gè)新值,其余依次更新。例4-3中兩個(gè)遞推變量
x1
和x2
更新:x1=x2;
x2=(2.0*x1+x/(x1*x1))/3.0;例4-4中的兩個(gè)遞推變量
a
和
b
借助一個(gè)臨時(shí)變量更新:tmp=b;
b=b+a;
a=tmp;可把
b
看成是“走在前面”的變量,a
依次緊隨其后,兩個(gè)變量亦步亦趨。41寫循環(huán)時(shí)要考慮和解決問題列表:循環(huán)涉及到哪些變量,需引進(jìn)哪些臨時(shí)性變量?循環(huán)如何開始?循環(huán)開始前給變量什么初值?循環(huán)中變量的值如何改變?什么情況下繼續(xù)(或終止)循環(huán)?循環(huán)終止后如何得到所需結(jié)果?用哪種結(jié)構(gòu)實(shí)現(xiàn)循環(huán),等等。工作方式:分析問題,發(fā)掘線索,最終完成程序。程序設(shè)計(jì)不是教條,典型問題也無標(biāo)準(zhǔn)答案。并非最簡單的問題總有多種解決方法,往往各有長短?!罢_”程序常有優(yōu)劣之分。42目
錄4.1循環(huán)程序設(shè)計(jì)4.2常用標(biāo)準(zhǔn)庫函數(shù)4.3交互式程序設(shè)計(jì)中的輸入處理4.4程序設(shè)計(jì)實(shí)例4.5程序動(dòng)態(tài)除錯(cuò)方法(二)434.2.1庫函數(shù)基本C和C++語言很小,ANSIC定義了標(biāo)準(zhǔn)庫,其中提供最常用的與平臺(tái)無關(guān)的功能(各種常用函數(shù))。每個(gè)符合標(biāo)準(zhǔn)的C/C++系統(tǒng)都提供了標(biāo)準(zhǔn)庫。C標(biāo)準(zhǔn)庫頭文件:name.h,C++標(biāo)準(zhǔn)庫頭文件:cname通常還提供一些擴(kuò)充庫,以便使用特定硬件/特定系統(tǒng)的功能:擴(kuò)充庫不標(biāo)準(zhǔn),使用擴(kuò)充庫的程序依賴于具體系統(tǒng)。庫函數(shù)實(shí)現(xiàn)常用計(jì)算,可按規(guī)定方式調(diào)用,不必自己實(shí)現(xiàn)/不必關(guān)心怎樣實(shí)現(xiàn)。開發(fā)一次使所有用戶受益。4.2常用標(biāo)準(zhǔn)庫函數(shù)44LinusTorvaldsPleasereadthef*ckmanual!標(biāo)準(zhǔn)庫功能包括輸入輸出、文件操作、存儲(chǔ)管理,其他如數(shù)學(xué)函數(shù)、數(shù)據(jù)轉(zhuǎn)換函數(shù)等。有關(guān)介紹散布在各章。下面介紹兩組常用標(biāo)準(zhǔn)函數(shù):程序計(jì)時(shí),隨機(jī)數(shù)。對(duì)庫函數(shù)的詳細(xì)用法,可查閱系統(tǒng)聯(lián)機(jī)幫助,或上網(wǎng)查閱有關(guān)手冊(cè)、參考書籍。需要耐心閱讀并練習(xí)范例程序。國際上知名的編程高手林納斯·托瓦茲通常都很耐心地回答別人提出的問題。但是有一次被人問了太多的入門級(jí)簡單問題之后,忍不住脫口而出“Pleasereadthef*ckmanual!”454.2.2程序計(jì)時(shí)統(tǒng)計(jì)程序/程序片段的計(jì)算時(shí)間有助于理解程序性質(zhì)。許多語言或系統(tǒng)都提供了內(nèi)部計(jì)時(shí)功能。使用程序計(jì)時(shí)功能,程序頭部需要寫:
#include<ctime>做程序計(jì)時(shí),通常需要用到:庫函數(shù)
clock()。用于返回從“開啟這個(gè)程序進(jìn)程”時(shí)刻到“程序中調(diào)用clock()函數(shù)”時(shí)刻之間的CPU時(shí)鐘計(jì)時(shí)單元(clocktick)數(shù)目。符號(hào)常量CLOCKS_PER_SEC:表示一秒鐘會(huì)有多少個(gè)時(shí)鐘計(jì)時(shí)單元。46程序計(jì)時(shí)的用法在程序中需要計(jì)時(shí)的起始點(diǎn)和結(jié)束點(diǎn)分別調(diào)用clock()函數(shù),得到這兩次調(diào)用該函數(shù)的返回值(可能需要用變量保存。假設(shè)為t0
和t1);用這兩次返回值之差除以符號(hào)常量CLOCKS_PER_SEC:
(double)(t1–t0)/CLOCKS_PER_SEC 就得到計(jì)時(shí)起始點(diǎn)和結(jié)束點(diǎn)之間所經(jīng)歷的時(shí)間,所得結(jié)果以秒為單位。每個(gè)系統(tǒng)有一個(gè)最小時(shí)間單位,小于這個(gè)時(shí)間單位的計(jì)時(shí)值都是0,計(jì)時(shí)結(jié)果也是以這個(gè)時(shí)間單位步進(jìn)增長的。所以得到的計(jì)時(shí)值只能作為參考。47【例4-6】程序中經(jīng)常要用到cout<<方法進(jìn)行屏幕打印輸出,那么單次執(zhí)行cout<<屏幕打印輸出一個(gè)整數(shù)要花費(fèi)多少時(shí)間呢?編程思路:多次執(zhí)行cout<<輸出,統(tǒng)計(jì)求平均。#include<iostream>#include<ctime>usingnamespacestd;intmain(){intt0,t1;constintNUM=50000;
t0=clock();//計(jì)時(shí)起始點(diǎn)
for(inti=0;i<NUM;i++)cout<<i<<endl;
t1=clock();//計(jì)時(shí)結(jié)束點(diǎn)
cout<<"Timeelapsed:"<<(double)(t1-t0)/CLOCKS_PER_SEC<<"s"<<endl;cout<<"perexcution:"<<1000.0*
(t1-t0)/CLOCKS_PER_SEC/NUM<<"ms"<<endl;return0;}48在標(biāo)準(zhǔn)庫中還有庫函數(shù)time(),取得從格林威治時(shí)間1970年1月1日零時(shí)整開始計(jì)時(shí)所經(jīng)過的時(shí)間,以秒為單位。誤差比較大。用法舉例:t1=time(0);(這個(gè)函數(shù)常常用于其它用途)494.2.3隨機(jī)數(shù)生成函數(shù)應(yīng)用有時(shí)需要帶隨機(jī)性的計(jì)算,為此需要生成隨機(jī)數(shù):程序調(diào)試:用數(shù)據(jù)做運(yùn)行試驗(yàn),隨機(jī)數(shù)據(jù)非常合適。計(jì)算機(jī)模擬:模擬實(shí)際情況/過程,探索規(guī)律性??陀^事物變化有隨機(jī)性。計(jì)算機(jī)只能生成“偽隨機(jī)數(shù)”。常用方法是定義某種遞推關(guān)系,設(shè)法使序列中的數(shù)比較具有隨機(jī)性??梢愿鶕?jù)這種方法定義隨機(jī)數(shù)生成函數(shù)(…)。50使用標(biāo)準(zhǔn)庫的隨機(jī)數(shù)功能,程序需包含頭文件:
#include<cstdlib>相關(guān)功能:函數(shù)srand: voidsrand(unsignedseed)功能:用seed值設(shè)種子值。默認(rèn)初始種子值是1。常用技巧:用當(dāng)前時(shí)間做種子:srand(time(0));隨機(jī)數(shù)生成函數(shù):intrand(void)功能:無參數(shù),根據(jù)
當(dāng)前種子值
生成一個(gè)介于
0和
符號(hào)常量
RAND_MAX
(該數(shù)值與系統(tǒng)有關(guān))
之間的隨機(jī)整數(shù),并設(shè)定該數(shù)為新種子值。 例:k=rand();51把隨機(jī)數(shù)轉(zhuǎn)換到一個(gè)自定義的范圍:轉(zhuǎn)換到整數(shù)區(qū)間[min,max]:(假設(shè)具體題目中給出的兩個(gè)數(shù)值min和max)
k=rand()%(max+1-min)+min;轉(zhuǎn)換到[0,1]實(shí)數(shù):rand()*1.0/RAND_MAX轉(zhuǎn)換到實(shí)數(shù)區(qū)間[dmin,dmax]: x=double(rand())/RAND_MAX*(dmax-dmin) +dmin;
52【例4-7】打印輸出在使用當(dāng)前時(shí)間作為種子值之后產(chǎn)生的40個(gè)處于[0,RAND_MAX]范圍內(nèi)的整數(shù)隨機(jī)數(shù)和40個(gè)處于區(qū)間[-5.5,10.5]內(nèi)的實(shí)數(shù)隨機(jī)數(shù),每行輸出5個(gè)數(shù)字時(shí)換行。#include<iostream>#include<ctime>//使用time()函數(shù)所需的庫文件#include<cstdlib>//使用隨機(jī)數(shù)函數(shù)所需的庫文件usingnamespacestd;intmain(){inti,k;cout<<"產(chǎn)生從0到"<<RAND_MAX<<"的整數(shù)隨機(jī)數(shù):"<<endl;
srand(time(0));for(i=0;i<40;i++){
k=rand();cout<<k<<(i%5==4?'\n':'\t');}設(shè)置一次種子數(shù),然后輸出一批隨機(jī)數(shù)53
cout<<endl<<endl;doublex,dmin=-5.5,dmax=10.5;cout<<"從"<<dmin<<"到"<<dmax<<"的實(shí)數(shù)隨機(jī)數(shù):"<<endl;
srand(time(0));for(i=0;i<40;i++){x=double(rand())/RAND_MAX*(dmax-dmin)+dmin;cout<<fixed<<x<<(i%5==4?'\n':'\t');}return0;}定義了變量dmin和dmax,使程序更有通用性,方便將來修改使用。54附加說明程序中只要包含頭文件cstdlib,就可以使用C語言標(biāo)準(zhǔn)庫(standardlibrary)的功能:五種類型:size_t、wchar_t、div_t、ldiv_t和lldiv_t;宏,例如EXIT_FAILURE、EXIT_SUCCESS、RAND_MAX
和MB_CUR_MAX等等;常用函數(shù),例如rand()、srand()、malloc()、calloc()、realloc()、free()、system()、atoi()、atol()、exit()
等等。55目錄4.1循環(huán)程序設(shè)計(jì)4.2常用標(biāo)準(zhǔn)庫函數(shù)4.3交互式程序設(shè)計(jì)中的輸入處理4.3.1通過計(jì)數(shù)器控制循環(huán)輸入4.3.2用結(jié)束標(biāo)志控制的循環(huán)輸入4.3.3輸入函數(shù)的返回值及其作用4.3.4字符串流與文件流輸入輸出4.3.5字符輸入輸出與字符相關(guān)函數(shù)4.4程序設(shè)計(jì)實(shí)例4.5程序動(dòng)態(tài)除錯(cuò)方法(二)高級(jí)語言程序設(shè)計(jì)第四章
基本程序設(shè)計(jì)技術(shù)564.3交互式程序設(shè)計(jì)中的輸入處理程序可以分為兩類:啟動(dòng)后自己運(yùn)行,可能提供一些輸出之后結(jié)束;執(zhí)行中需要不斷與外界(用戶)打交道,需要外界提供信息,這類程序稱為交互式程序(有輸入的程序都可以看作交互式程序)。前文中的很多程序都是簡單的交互式程序,只要求用戶輸入一兩個(gè)數(shù)據(jù)即可。如果程序中需要輸入較多的數(shù)據(jù),那么就需要考慮一些相應(yīng)的處理方法才行。574.3.1通過計(jì)數(shù)器控制循環(huán)輸入 如果事先知道需要輸入的數(shù)據(jù)項(xiàng)數(shù),就可以用計(jì)數(shù)器控制輸入循環(huán)。4.3.2用結(jié)束標(biāo)志控制的循環(huán)輸入 假定寫程序時(shí)不知道需要輸入的數(shù)據(jù)的確切項(xiàng)數(shù),就無法采用計(jì)數(shù)循環(huán)的簡單方法。需要使用結(jié)束標(biāo)志。4.3.3輸入函數(shù)的返回值及其作用
當(dāng)上面兩種方式都不能用時(shí),需要使用輸入函數(shù)的返回值,判斷是否繼續(xù)輸入。4.3.4字符串流與文件流輸入輸出一、使用字符串類進(jìn)行輸入輸出二、使用流式文件進(jìn)行輸入輸出584.3.1通過計(jì)數(shù)器控制循環(huán)輸入如果事先知道需要輸入的數(shù)據(jù)項(xiàng)數(shù),可以用計(jì)數(shù)器控制輸入循環(huán)?!纠?-8】假設(shè)用戶手頭有一批double類型的數(shù)據(jù),寫一個(gè)程序,讓用戶先輸入數(shù)據(jù)總項(xiàng)數(shù),然后依次輸入這些數(shù)據(jù),最后求出所有這些數(shù)據(jù)的總和并輸出。這一程序中的輸入操作可以通過一個(gè)計(jì)數(shù)的輸入循環(huán)完成:59intmain(){inti,n;doublex,sum;cout<<"Pleaseinputnumberofdataitems:";
cin>>n;for(i=1,sum=0;i<=n;++i){ //計(jì)數(shù)器cout<<i<<":";
cin>>x; //輸入sum+=x;}cout<<"Sum="<<sum<<endl;return0;}60intmain(){inti,n;doublex,sum;
cout<<"Pleaseinputnumberofdataitems:";
cin>>n;for(i=1,sum=0;i<=n;++i){ //計(jì)數(shù)器
cout<<i<<":";
cin>>x; //輸入sum+=x;}cout<<"Sum="<<sum<<endl;return0;}良好的編程習(xí)慣:輸入之前顯示提示信息如果缺少提示信息,則程序開始運(yùn)行就等待用戶輸入,用戶可能也不知道程序在干啥,互相傻等著對(duì)方。
614.3.2用結(jié)束標(biāo)志控制的循環(huán)輸入假定寫程序時(shí)不知道需要輸入的數(shù)據(jù)的確切項(xiàng)數(shù),就無法采用計(jì)數(shù)循環(huán)的簡單方法。一種方式是用一個(gè)特殊“結(jié)束標(biāo)志”控制循環(huán)。該“結(jié)束標(biāo)志”應(yīng)是一個(gè)特殊輸入值,具有與輸入數(shù)據(jù)同樣的類型,但又不是正常輸入數(shù)據(jù)。讓程序在循環(huán)中不斷檢測得到的數(shù)據(jù),一旦看到這個(gè)特殊數(shù)據(jù),就知道用戶要求結(jié)束了。采用這種技術(shù),循環(huán)結(jié)束條件就是編程者與使用者之間的一種約定,當(dāng)輸入滿足約定時(shí)程序就結(jié)束。62【例4-9】假定需要計(jì)算一批貨物的總值,每次輸入的是貨物單價(jià)和數(shù)量。由于并不知道需要算的貨物種類,因此無法使用計(jì)數(shù)循環(huán)??梢钥紤]用一種特殊“結(jié)束標(biāo)志”通知程序所有數(shù)據(jù)都已輸入完。例如用單價(jià)為0作為結(jié)束標(biāo)志(因?yàn)樵趯?shí)踐中不可能有貨物的單價(jià)為0):intmain(){doubleprice=1,amount,sum=0;cout<<"依次輸入貨物的單位和數(shù)量(00結(jié)束)"<<endl;while(price!=0){ //用特殊標(biāo)志結(jié)束循環(huán)cout<<"輸入下一項(xiàng)數(shù)據(jù)(單價(jià)數(shù)量):";cin>>price>>amount;sum+=price*amount;}cout<<"Totalprice:"<<sum<<endl;return0;}634.3.3輸入函數(shù)的返回值及其作用在例4-9中,所輸入的貨物單價(jià)總應(yīng)該是正數(shù),因此可以用某個(gè)特殊值作為輸入結(jié)束標(biāo)志。在更一般的情況下,所輸入的數(shù)據(jù)涵蓋了可能的所有取值范圍,就無法選用某個(gè)特殊值作為輸入結(jié)束標(biāo)志了。需要通過輸入函數(shù)的返回值傳遞信息,以控制循環(huán)的結(jié)束。在使用cin>>進(jìn)行流式輸入時(shí),提取運(yùn)算符“>>”會(huì)返回一個(gè)值:用戶輸入一個(gè)合法的數(shù)據(jù)給后面的變量,就返回一個(gè)非零值。用戶輸入一個(gè)非法的數(shù)據(jù)時(shí),就會(huì)返回零值。這個(gè)返回值可以用在程序中用于判斷所輸入的數(shù)據(jù)是否合法,從而控制是否進(jìn)行其它操作。64【例4-10】請(qǐng)輸入一系列double類型的數(shù)據(jù)(總項(xiàng)數(shù)事先未知),對(duì)數(shù)據(jù)項(xiàng)數(shù)計(jì)數(shù),并求出所有數(shù)據(jù)的累加和。使用cin>>輸入數(shù)據(jù)時(shí)的返回值,寫出程序如下:intmain(){intn=0;doublex,sum=0;cout<<"inputx:";
while(
(cin>>x)
){//使用“>>”的返回值作循環(huán)控制
n++;sum+=x;cout<<"inputx:";}cout<<"n="<<n<<endl;cout<<"sum="<<sum<<endl;return0;}輸入非數(shù)值型數(shù)據(jù)時(shí)
(輸入字母,或按Ctrl+Z),輸入循環(huán)就會(huì)中止。65上面這個(gè)輸入方法也有別的用途。在交互式程序的實(shí)際運(yùn)行中,正常用戶也可能會(huì)出現(xiàn)操作失誤,這時(shí)需要程序能檢測到輸入錯(cuò)誤,允許用戶重新輸入。另一方面,也有可能某些用戶會(huì)惡意地輸入錯(cuò)誤數(shù)據(jù),程序應(yīng)該檢測到輸入錯(cuò)誤,強(qiáng)制用戶重新輸入合法數(shù)據(jù)?!纠?-11】在例4-7中,在運(yùn)行時(shí)有兩條語句(即“cin>>n;”和“cin>>x;”)要求用戶輸入數(shù)據(jù)。如果我們考慮到要防止用戶輸入錯(cuò)誤數(shù)據(jù)(例如在要求輸入數(shù)值型數(shù)據(jù)時(shí)卻輸入字符數(shù)據(jù)),可以在每次輸入時(shí)都進(jìn)行檢測,允許用戶輸入每項(xiàng)數(shù)據(jù)時(shí)允許最多出錯(cuò)三次,可以改寫成這樣:intmain(){inti,n;doublex,sum;intierr=0,ERRNUM=3;cout<<"請(qǐng)輸入數(shù)據(jù)項(xiàng)數(shù):";
while(!(cin>>n)||n<=0){//獲得輸入,并處理可能的出錯(cuò)情形ierr++;if(ierr<=ERRNUM){//輸入出錯(cuò)次數(shù)低于最大允許次數(shù)cin.clear();//清除錯(cuò)誤標(biāo)記cin.sync();//清空緩沖區(qū)cout<<"輸入出錯(cuò)"<<ierr<<"次。請(qǐng)重新輸入數(shù)據(jù)項(xiàng)數(shù):";}else{//輸入出錯(cuò)次數(shù)超過最大允許值cout<<"\n致命錯(cuò)誤:輸入出錯(cuò)超過"<<ERRNUM<<"次!\n";exit(1);//結(jié)束程序}}cin.sync();//成功獲得輸入數(shù)據(jù)之后,也要清空緩沖區(qū)cout<<"n="<<n<<endl;66for(i=1,sum=0;i<=n;++i){cout<<i<<":";ierr=0;while(!(cin>>x)){//獲得輸入,并處理可能的出錯(cuò)情形ierr++;if(ierr<=ERRNUM){//輸入出錯(cuò)次數(shù)低于最大允許次數(shù)cin.clear();//清除錯(cuò)誤標(biāo)記cin.sync();//清空緩沖區(qū)cout<<"輸入出錯(cuò)"<<ierr<<"次。請(qǐng)重新輸入數(shù)據(jù):";}else{//輸入出錯(cuò)次數(shù)達(dá)到最大允許次數(shù)cout<<"\n致命錯(cuò)誤:輸入出錯(cuò)超過"<<ERRNUM<<"次!\n";exit(1);//結(jié)束程序}}sum+=x;}cout<<"Sum="<<sum<<endl;return0;}6768對(duì)計(jì)算機(jī)的“輸入”行為詳細(xì)解釋??梢园褬?biāo)準(zhǔn)輸入(通常是鍵盤)看成一個(gè)綿延不斷的字符序列(字符流),鍵入回車鍵時(shí)就把前面所鍵入的字符序列存入到系統(tǒng)的緩沖區(qū)。程序里調(diào)用輸入函數(shù),就是想用掉該序列最前面的一個(gè)或幾個(gè)字符。例如,用
cin>>
輸入數(shù)值型數(shù)據(jù)時(shí)就會(huì)用掉序列前面的幾個(gè)字符(如果它們符合轉(zhuǎn)換要求)。輸入序列中的字符用掉一個(gè)就少一個(gè),未用的字符則仍然留在序列中。如果cin>>
工作中某個(gè)指定轉(zhuǎn)換失敗,就會(huì)返回一個(gè)錯(cuò)誤標(biāo)記,而輸入流中的字符序列仍然保持在讀入前的狀態(tài)(讀入失敗的字符沒有被用掉)。程序緩沖區(qū)42156abcd69對(duì)每次輸入都進(jìn)行檢測,如果出錯(cuò)次數(shù)少于ERRNUM次,則用cin.clear()
清除錯(cuò)誤標(biāo)記,用cin.sync()
清空緩沖區(qū)(這兩個(gè)操作必須配合一起使用),再提示用戶重新輸入。程序緩沖區(qū)abcd123456較為完善的處理:if(ierr<=ERRNUM){//輸入出錯(cuò)次數(shù)低于最大允許次數(shù)cin.clear();//清除錯(cuò)誤標(biāo)記cin.sync();//清空緩沖區(qū)cout<<"輸入出錯(cuò)"<<ierr<<"次。請(qǐng)重新輸入數(shù)據(jù)項(xiàng)數(shù):";}else{//輸入出錯(cuò)次數(shù)達(dá)到最大允許次數(shù)cout<<"\n致命錯(cuò)誤:輸入出錯(cuò)超過"<<ERRNUM<<"次!\n";exit(1);//結(jié)束程序}70輸入出錯(cuò)次數(shù)太多,則用exit
函數(shù)使程序結(jié)束運(yùn)行,返回到操作系統(tǒng)。——通常用exit(0)表示程序正常退出,exit(1)
表示程序異常退出。程序緩沖區(qū)abcd123456if(ierr<=ERRNUM){//輸入出錯(cuò)次數(shù)低于最大允許次數(shù)cin.clear();//清除錯(cuò)誤標(biāo)記cin.sync();//清空緩沖區(qū)cout<<"輸入出錯(cuò)"<<ierr<<"次。請(qǐng)重新輸入數(shù)據(jù)項(xiàng)數(shù):";}else{//輸入出錯(cuò)次數(shù)達(dá)到最大允許次數(shù)cout<<"\n致命錯(cuò)誤:輸入出錯(cuò)超過"<<ERRNUM<<"次!\n";exit(1);//結(jié)束程序}714.3.4字符串流與文件流輸入輸出如果多次運(yùn)行程序,可能需要多次重復(fù)輸入數(shù)據(jù)。能否只輸入一次數(shù)據(jù),以后重復(fù)使用數(shù)據(jù)呢?C或C++都可以用字符串或文件進(jìn)行輸入輸出。C語言為此提供了一整套標(biāo)準(zhǔn)庫函數(shù):sprintf:輸出到字符串sscanf:從字符串輸入fprintf:輸入到文件fscanf:從文件輸入C++提供了流式輸入輸出,用法比C語言的上述標(biāo)準(zhǔn)庫函數(shù)更為簡單方便。C++對(duì)
C
的一個(gè)重要改進(jìn)就是提供了流式輸入輸出。流(stream)就是有窮或無窮長的一串字符形成的序列,可以作為輸入操作的對(duì)象,也可以接收輸出操作的產(chǎn)出。72cin是標(biāo)準(zhǔn)輸入流,cout是標(biāo)準(zhǔn)輸出流。也可用
字符串
和
文件
作為輸入流和輸出流。源目標(biāo)>><<程序程序輸入流輸出流流式輸入輸出采用統(tǒng)一的描述形式(通過提取運(yùn)算符“>>”和插入運(yùn)算符“<<”),能夠根據(jù)接受輸入的變量或提供輸出內(nèi)容的表達(dá)式正確完成數(shù)據(jù)轉(zhuǎn)換,因此更加易用和安全。73字符串可以用作輸入輸出的對(duì)象,C++標(biāo)準(zhǔn)庫提供了與字符串輸入輸出有關(guān)的功能。程序中需要包含頭文件sstream:
#include<sstream>利用
istringstream
類的對(duì)象可以把字符串轉(zhuǎn)化為輸入流。例如定義一個(gè)字符串輸入流變量并用字符串對(duì)其初始化:
istringstreaminss("362512426455");
字符串輸入流變量字符串也可先定義一個(gè)字符數(shù)組并存入一個(gè)字符串(見第6章),再將其綁定到字符串輸入流(略)對(duì)于字符串輸入流,可以類似于cin一樣用提取運(yùn)算符“>>”進(jìn)行輸入操作。例如:
inss>>n;
//從inss中讀取一個(gè)數(shù)據(jù)并賦給整型變量n74【例4-12】對(duì)于例4-8,在程序中改用一個(gè)istringstream類的變量存儲(chǔ)一些示例數(shù)據(jù)用作輸入源,實(shí)現(xiàn)該例的功能:先讀入數(shù)據(jù)總項(xiàng)數(shù),然后依次讀入數(shù)據(jù),最后求出所有這些數(shù)據(jù)的總和并輸出。#include<iostream>#include<sstream>usingnamespacestd;intmain(){inti,n;doublex,sum;
istringstreaminss("81.23.56.44.78.910.55.89.4");//定義字符串輸入流變量并綁定到字符串示例數(shù)據(jù)
inss>>n;cout<<"numberofdataitems:"<<n<<endl;for(i=1,sum=0;i<=n;++i){
inss>>x;cout<<i<<":"<<x<<endl;sum+=x;}cout<<"Sum="<<sum<<endl;return0;}根據(jù)后續(xù)語句的功能而設(shè)定初始值!第一個(gè)數(shù)字為數(shù)據(jù)個(gè)數(shù),后續(xù)為數(shù)據(jù)。#include<iostream>#include<sstream>usingnamespacestd;intmain(){inti,n;doublex,sum;
istringstreaminss("81.23.56.44.78.910.55.89.4");//定義字符串輸入流變量并綁定到字符串示例數(shù)據(jù)
inss>>n;cout<<"numberofdataitems:"<<n<<endl;for(i=1,sum=0;i<=n;++i){
inss>>x;cout<<i<<":"<<x<<endl;sum+=x;}cout<<"Sum="<<sum<<endl;return0;}75注意:計(jì)算機(jī)只能按順序從前往后地依次讀取數(shù)據(jù)!有個(gè)別同學(xué)認(rèn)為,字符串里的數(shù)據(jù)可以隨便排列,計(jì)算機(jī)會(huì)聰明地先讀取出數(shù)據(jù)總數(shù),然后再依次逐個(gè)讀取數(shù)據(jù)。但是,計(jì)算機(jī)總是呆板地按照程序工作的!編程者必須仔細(xì)地排列好數(shù)據(jù),并仔細(xì)地安排計(jì)算機(jī)依次讀取數(shù)據(jù)。76二、使用流式文件進(jìn)行輸入輸出把待輸入的數(shù)據(jù)一次性寫在一個(gè)字符串中,不再需要每次都重復(fù)輸入數(shù)據(jù),減輕了調(diào)試工作的麻煩。這是它的優(yōu)點(diǎn)。但不足之處在于,數(shù)據(jù)被寫在程序內(nèi)部,只有編程者能修改數(shù)據(jù),不懂得編程的用戶就沒法使用這個(gè)程序了??紤]到這一點(diǎn),“數(shù)據(jù)與程序分離”就變得很有必要了。為此,有必要使用文件作為輸入源。計(jì)算機(jī)系統(tǒng)通常以樹形結(jié)構(gòu)的多級(jí)目錄(文件夾)的形式管理所有文件。文件的名稱包含主名和擴(kuò)展名兩部分,用“.”分隔。通常用合適的擴(kuò)展名說明文件類型。同一種文件使用相同的擴(kuò)展名。77Windows系統(tǒng)的文件資源管理器默認(rèn)隱藏文件的擴(kuò)展名。編程人員應(yīng)該看到完整的文件名為好:在文件資源管理器中,在“查看”下面勾選“文件擴(kuò)展名”。(編程者應(yīng)當(dāng)對(duì)計(jì)算機(jī)中的文件有基本的了解)78在C++程序中,要使用計(jì)算機(jī)中的文件作為讀取數(shù)據(jù)的來源或輸出數(shù)據(jù)的目標(biāo),就需要把相應(yīng)的文件綁定為文件輸入輸出流。C++引入了相關(guān)的類型:ifstream類——文件輸入流;ofstream類——文件輸出流;fstream類——文件輸入輸出流。程序中必須包含頭文件<fstream>:#include<fstream>定義一個(gè)文件輸入流的方法如下: ifstreaminfile; //infile為文件輸入流的名稱要想通過一個(gè)文件輸入流對(duì)象打開一個(gè)純文本文件,需要使用它的成員函數(shù)open(): infile.open(“data.txt”)//“data.txt”為純文本文件也可以直接定義文件輸入流并同時(shí)綁定純文本文件: ifstreaminfile("data.txt");然后就可以像使用cin一樣從文件輸入流讀取數(shù)據(jù): infile>>n;infile>>x;7980類似的,定義一個(gè)文件輸出流、并綁定純文本文件:
ofstreamoutfile("output.txt");
文件輸出流
可供輸出數(shù)據(jù)的文件然后就可以把outfile類似于cout一樣使用插入運(yùn)算符“<<”進(jìn)行輸出操作。例如:
outfile<<n; //把整型變量n的值輸出到outfile:打開的文件使用完成后一定要關(guān)閉,fstream提供了成員函數(shù)close()來完成此操作: infile.close(); outfile.close();只含人類可讀字符的文件81【例4-13】對(duì)于例4-10,在程序中改用一個(gè)文本文件存儲(chǔ)一些示例數(shù)據(jù)用作輸入源,實(shí)現(xiàn)該例的功能:讀入一系列double類型的數(shù)據(jù)(總項(xiàng)數(shù)事先未知),對(duì)數(shù)據(jù)項(xiàng)數(shù)計(jì)數(shù),并求出所有數(shù)據(jù)的累加和。#include<iostream>#include<fstream>usingnamespacestd;intmain(){intn=0;doublex,sum=0;ifstreaminfile("data.txt");if(!infile){//如果輸入文件流創(chuàng)建出錯(cuò)
cout<<"ERROR:can'topeninputfile."<<endl;exit(1);}事先要編輯這個(gè)文件,在里面寫一些數(shù)據(jù),并保存到本程序所在的同一文件夾中。如果沒有這個(gè)文件,或者這個(gè)文件未保存在本程序所在的同一文件夾中,都會(huì)出錯(cuò)。82
cout<<"readdatafrominputfile:"<<endl;while((infile>>x)){n++; sum+=x;cout<<x<<endl;}infile.close();ofstreamoutfile("output.txt");
if(!outfile){//如果輸出文件流創(chuàng)建出錯(cuò)
cout<<"ERROR:can'topenoutputfile."<<endl;exit(1);}
outfile<<"n="<<n<<endl;
outfile<<"Sum="<<sum<<endl;
outfile.close();cout<<"resultssavedinfileoutput.txt"<<endl;return0;}這個(gè)文件將被創(chuàng)建在本程序所在的同一文件夾中。程序正常運(yùn)行之后,可在本程序所在文件夾中找到此文件并打開查看其內(nèi)容。83數(shù)據(jù)文件通常需要存放在源程序文件所在的同一個(gè)文件夾中。如果數(shù)據(jù)文件存放在與源程序文件不同的另一個(gè)文件夾中,就需要指定它的完整路徑(詳細(xì)存放位置):在Windows系統(tǒng)中,文件完整路徑包括:硬盤分區(qū)的盤符+各級(jí)文件夾+文件全名。(用
\
分隔)例如(在C/C++的字符串中,用轉(zhuǎn)義序列
\\
表示
\):ifstreaminfile("d:\\myprog\\data.txt");
盤符
各級(jí)文件夾
文件全名C/C++也支持使用
/
作為分隔符(以簡化描述):ifstreaminfile("d:/myprog/data.txt");844.3.5字符輸入輸出與字符相關(guān)函數(shù)上面討論的都是數(shù)值型數(shù)據(jù)的輸入。接下來討論字符型數(shù)據(jù)的輸入和輸出。一、從標(biāo)準(zhǔn)設(shè)備輸入和輸出字符字符型數(shù)據(jù)也可以用cin>>輸入,用cout<<方式輸出:charch;cin>>ch; //不能接收空格鍵和回車鍵。cout<<ch;85把鍵盤上輸入的每個(gè)字符(包括空格和回車鍵)都作為一個(gè)輸入字符給字符型變量時(shí)的辦法:使用標(biāo)準(zhǔn)庫函數(shù)中專門用于輸入字符getchar函數(shù);使用標(biāo)準(zhǔn)輸入流對(duì)象cin的成員函數(shù)get,它也專門用于輸入字符的函數(shù),在使用時(shí)寫成cin.get的形式。這兩者的功能基本上是等價(jià)的,用戶任選使用。用法:getchar
和cin.get
都是沒有參數(shù)的函數(shù)(簡稱“無參函數(shù)”),它們都能從標(biāo)準(zhǔn)輸入讀一個(gè)字符,返回該字符的編碼值。其類型特征描述為:
int
getchar(void)
int
cin.get(void)是int類型而非char類型86標(biāo)準(zhǔn)庫定義了一個(gè)符號(hào)常量EOF(意為“EndOfFile”,文件結(jié)束),getchar和cin.get在讀字符時(shí)如果遇到文件結(jié)束(或輸入結(jié)束),就返回EOF的值,說明已經(jīng)沒有輸入了。在實(shí)際運(yùn)行程序時(shí),通常用組合鍵Ctrl+Z輸入EOF。一般系統(tǒng)里把EOF的值定義為-1。符號(hào)常量EOF
的值必須與任何字符的編碼值都不相同(否則就會(huì)產(chǎn)生混亂)。所以C和C++標(biāo)準(zhǔn)庫里把getchar和cin.get的返回值類型定義為int(而不是char)。同樣,調(diào)用getchar和cin.get時(shí)也應(yīng)當(dāng)用int類型的變量接收其返回值,這樣才能保證EOF信息不丟失,保證文件結(jié)束判斷的正確性。87getchar和cin.get的典型使用:int
ch;ch=getchar(); //空括號(hào)不可少ch=cin.get();這兩個(gè)語句都能從標(biāo)準(zhǔn)輸入讀一個(gè)字符,并把字符的編碼賦給變量ch。默認(rèn)情況下標(biāo)準(zhǔn)輸入連到鍵盤,因此,當(dāng)程序執(zhí)行到這個(gè)getchar或cin.get調(diào)用時(shí),該函數(shù)將從鍵盤取字符。如果沒有已經(jīng)鍵入的字符,程序就會(huì)等待,直到人通過鍵盤輸入字符,并按過回車鍵之后,函數(shù)getchar或cin.get才能得到結(jié)果,語句完成后程序繼續(xù)運(yùn)行下去。88輸出字符:標(biāo)準(zhǔn)庫中的putchar
和cout的成員函數(shù)put(寫作cout.put
)專門用于輸出字符。功能等價(jià),用戶在實(shí)際應(yīng)用中可以任選一種方式。例如: putchar('O'); cout.put('K');程序運(yùn)行時(shí),兩個(gè)字符‘O’和‘K’將被依次送到標(biāo)準(zhǔn)輸出,因此,執(zhí)行這兩個(gè)語句的效果是在計(jì)算機(jī)屏幕上顯示出“OK”。通??梢杂胏out<<的方式輸出,所以很少使用putchar和cout.put。89在程序中如果需要以循環(huán)方式輸入一系列字符,可以按照前文所說的三種方法來處理:1.事先已知輸入字符的個(gè)數(shù)時(shí),用固定次數(shù)的循環(huán);2.事先未知待輸入字符的個(gè)數(shù)時(shí),可用特殊標(biāo)志來控制循環(huán),3.也可以用函數(shù)的返回值來控制(通常用EOF來結(jié)束)?!纠?-14】輸入一系列字符,然后逐個(gè)輸出,并輸出字符相對(duì)應(yīng)的ASCII值,最后輸出字符個(gè)數(shù)。請(qǐng)考慮是以回車符結(jié)束或者允許接受回車符。90借鑒前文講到的“以輸入函數(shù)的返回值”方法,寫出程序:#include<iostream>usingnamespacestd;intmain(){intch,n=0;cout<<"pleaseinputsomechars:"<<endl;while((ch=cin.get())!='\n'){//以回車符為結(jié)束標(biāo)志
//while((ch=cin.get())!=EOF){//以EOF為結(jié)束標(biāo)志
cout<<(char)ch<<"\t"<<ch
<<endl;++n;}cout<<"Totallyget"<<n<<"chars."<<endl;return0;}兩種寫法,可任選使用其中一種(另一種設(shè)為注釋)91程序執(zhí)行時(shí)進(jìn)入等待狀態(tài),等待輸入字符。用戶由鍵盤輸入一個(gè)字符并按回車鍵后,程序?qū)演斎氲淖址捌湎鄳?yīng)的ASCII值輸出到屏幕。以回車符為結(jié)束標(biāo)志時(shí),所輸入的回車符并不被認(rèn)為是輸入字符,程序正常結(jié)束。以EOF為結(jié)束標(biāo)志時(shí),所輸入的回車符仍被認(rèn)為是輸入字符(并輸出),用戶還可以繼續(xù)輸入,直到在新的一行輸入中按下Ctrl+Z并鍵入回車鍵為止。以兩種方式輸出變量ch:
cout<<
(char)ch
<<"\t"<<ch
<<endl;
while((ch=cin.get())
!=
'\n')while((ch=cin.get())!=
EOF)強(qiáng)制類型轉(zhuǎn)換為char類型再輸出,所輸出的是一個(gè)字符直接輸出所輸入字符的ASCII碼92二、從字符流和文件流輸入輸出字符也可以從字符串流和文件流輸入字符,或者向字符串流和文件流輸出字符:用>>
進(jìn)行輸入,
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(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ǔ)空間,僅對(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ì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 旅游行業(yè)行程變動(dòng)及責(zé)任豁免協(xié)議書
- 電子支付平臺(tái)開發(fā)與推廣合作協(xié)議
- 營業(yè)辦公用房買賣協(xié)議書
- 中學(xué)生感恩教育故事觀后感
- 高考語文高頻文言實(shí)詞60詞表解
- 環(huán)保能源行業(yè)項(xiàng)目合作風(fēng)險(xiǎn)提示
- 高考語文備考之明朝作家文言文匯編(下)
- 購銷家具合同家具購銷合同
- 綠色農(nóng)業(yè)種植合同
- 裝修工程勞務(wù)外包合同
- 2019年四川省綿陽市中考化學(xué)試卷
- 中國風(fēng)青花瓷陶瓷文化宣傳PPT模板
- 美麗鄉(xiāng)村規(guī)劃設(shè)計(jì)技術(shù)導(dǎo)則
- 課題成果要報(bào)格式和要求
- 經(jīng)銷商準(zhǔn)入及評(píng)定表格vr
- SF-36量表(簡明健康狀況調(diào)查表)
- 主要河流南、北方河流的不同特征主要湖泊
- 上崗證WORD模板
- 2019第五版新版PFMEA 注塑實(shí)例
- 職業(yè)技能鑒定質(zhì)量督導(dǎo)報(bào)告
- 鈑金k因子和折彎扣除參照表
評(píng)論
0/150
提交評(píng)論