格式化輸入與輸出:
#include <stdio.h>
int main(){
int x,n = 0,min,max,s = 0;
while(scanf("%d,&x)==1){
s += x;
if(x<min) min = x;
if(x>max) max = x;
n++;
}
printf("%d %d %.3f\n",min,max,(double)s/n);
return 0;
}
- 首先我們在使用快速讀入時,我們采用了scanf()格式化的輸入,我們會存在這樣的疑問,scanf()函數有傳回值?答案是有的,傳回的是成功輸入的變量的個數,當輸入結束時,scanf()函數将無法繼續讀取x,将傳回0;
- 但是當我們測試輸入:"2 8 3 5 1 7 3 6"發現,并沒有任何結果,是程式運作速度太慢?我們等待一會,發現還是沒有結果,其實問題出在,程式認為我們還是沒有輸入完,對于scanf()函數來說,空格、TAB和回車符都是無關緊要的,是以程式沒有結束,我們如何結束呢?
-
1)在Win系統下,我們在輸入完畢先按Enter鍵,再按Ctrl+Z鍵,最後再按Enter鍵即可結束。
2)在Linux下,輸入完畢後按下Ctrl+D鍵即可結束輸入。
- 解決了上面的問題,我們運作會發現,我們的min,max還是沒有更新成我們想要的值,或是當我們換一台電腦測試時,我們的答案是不一樣的。其實不難知道,我們在定義min和max時就出現了我們,我們要求最小值min,那剛開始就應該給它賦一個很大的值,最大值max同理可得。我們可以定義一個常量INF=1000000000,否則min,max定義在主函數裡面,會被配置設定一個随機值,因為這個時候定義的變量是定義在棧裡面的也沒有賦初值,還存在如果這個所謂的最大值,最小值可能不夠大,或是不夠小,這個問題我們後面會繼續讨論;
- 可是今天主題是算法競賽中的輸入輸出架構 好像沒有太大的關系啊,其實不然,類似上面的程式,我們在測試的時候,每一次都要手動輸入很多的資料,每次的資料其實隻是在指令行運作了一次之後就沒有,很不友善。
一個好的方法
- 把輸入輸出資料儲存在檔案裡面,就不必每次重新輸入了,輸出的時候也到檔案裡,避免了篇幅太大,也友善了我們和标準答案的對比。
使用檔案的方法
比賽中大量的選手往往因為檔案相關的問題丢掉大量分數,例如:輸入、輸出檔案名和程式名,往往比賽都對其有着嚴格的規定,不要弄錯大小寫,不要拼錯檔案名,不要使用絕對路徑或相對路徑
-
最簡單的方法–輸入輸出重定向freopen版
- freopen是使用檔案最簡單的方法,隻需要在main函數的入口處加入以下兩條語句:
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
- 上述語句将使得scanf()從檔案input.txt讀入,printf寫入檔案out.txt。其實,通過freopen實作檔案的讀入和輸出後,所有的鍵盤讀入和螢幕輸出都将改成檔案的操作;
- 事實上在算法競賽中,feropen這樣的重定向方式讀寫檔案,有的時候是不允許的 ,比賽前選手需要仔細閱讀檔案讀入的相關規定
-
最保險的方法–輸入輸出fopen版
- 如果比賽要求用檔案輸入輸出,但禁止用重定向的方式,我們就可以采用fopen()方式
#include <cstdio> const int INF 10000000000 int main(){ FILE *fin,*fout; fin = fopen("data.in","rb"); fout = fopen("data.out","wb"); int x,n = 0,min = INF,max = -INF,s = 0; while(fscanf(fin,"%d",&x)==1){ s += x; if(x<min) min = x; if(x>max) max = x; n++; } fprintf(fout,"%d %d %.3f\n",min,max,(double)s/n); fclose(fin); fclose(fout); returm 0; }
- 上述代碼,我們首先定義了fin,fout,暫且不用考慮FILE*,把scanf改成fscanf,對應的第一個參數為fin;把printf改成fprintf,第一個參數為fout,最後執行fclose關閉兩個檔案
小結
- 重定向和fopen兩種方法各有優勢,重定向方法寫起來簡單,但是競賽中有可能被禁用,這時候我們就需要選用fopen版本進行檔案的讀寫操作
- 重定向版本寫起來簡單、自然,但是不能同時讀寫檔案和标準輸入輸出;fopen的寫法稍顯繁瑣,但是靈活性比較大,當我們想把fopen版本的程式改成讀寫标準輸入輸出,隻需複制“”“fin = stdin;fout = stdout;”
- 例如:
//使用檔案輸入輸出,但當禁止使用重定向的方式時,采用如下方法
//此時為檔案讀入,标準輸出
#include<iostream>
#include<cstdio>
#include<fstream>
using namespace std;
int main()
{
FILE *fin,*fout;
fin=fopen("input.txt","rb"); //檔案讀取
//fout=fopen("output.txt","wb"); //輸出到檔案
//fin=stdin; //把fopen版的程式改成讀寫标準輸入輸出
fout=stdout;
int x,n=0,min=100,max=-100,s=0;
while(fscanf(fin,"%d",&x)==1) //scanf變為fscanf
{
s+=x;
if(min>x) min=x;
if(max<x) max=x;
n++;
}
fprintf(fout,"%d %d %.3f\n",min,max,(double)s/n); //printf變為fprintf
fclose(fin); //關閉兩個檔案
fclose(fout);
return 0;
}
-
檔案輸入輸出流–輸入輸出stream版
- 在 C++中,檔案輸入流(ifstream)和檔案輸出流(ofstream)的類,預設是輸入輸出到磁盤檔案,C++可以在建立對象是,設定輸入輸出的檔案。在使用的時候需要利用 #include 引入 fstream頭檔案
-
使用定義如下:
ifstream fin(“輸入檔案名.擴充名”);
ofstream fout(“輸出檔案名.擴充名”);
#include <cstdio> const int INF 10000000000 int main(){ ifstream fin("input.txt"); ofstream fout("output.txt"); int temp,sum = 0; while(fin >> temp){ sum += temp; } fout << sum; fin.close(); fout.close(); return 0; }
- 上述代碼,我們首先定義了fin,fout,暫且不用考慮FILE*,把scanf改成fscanf,對應的第一個參數為fin;把printf改成fprintf,第一個參數為fout,最後執行fclose關閉兩個檔案