天天看點

NOIP常用三種輸入輸出架構

格式化輸入與輸出:

#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關閉兩個檔案

繼續閱讀