如果你對管道和重定向應用自如了,無需繼續往下看。本文雖然以windows上cmd命令行環境演示,但同樣適用於Unix/Linux等平臺。
/*************************************************************************
* 作者:xusiwei1236([email protected])
* 出處:http://blog.csdn.net/xusiwei1236
* 聲明:轉載請註明出處,請勿用於商用.
* 對本文所涉及的主題如有任何觀點、想法,歡迎交流(email或評論)
************************************************************************/
引言
關於管道和重定向,最初是在劉汝佳的《算法競賽入門經典》上看到的,也是從那時開始用gcc(MinGW) & notepad++(在此之前,Linux上用的是Eclipse+CDT,windows上是VC)。一般操作系統的命令行環境下都提供了管道和重定向工具,看了劉汝佳的書才知道用txt代替鍵盤作輸入、測試是多麼的方便!回想起每次點完GO之後一個數字一個數字的按鍵盤(而且筆記本鍵盤的數字鍵按起來沒有獨立鍵盤的數字區按起來那麼爽)還不時按錯的痛苦經歷,決定今日將這一強大的工具與大家分享。從A+B說起
練過OJ的同學可能對此深有體會(沒練過沒有關係),你的程序可能要先讀10個輸入(或者更多),纔出結果;而你有很難保證這個程序一次編譯就是對的,每次修改後都要重新輸入這一堆數(還時不時的輸錯),實在讓人難以忍受!劉的書中說了兩種方法:一.利用C標準庫提供的“重定向函數”freopen("input.txt", "r", stdin);這種方法適合用在IDE上,添加一行代碼,再準備一個文本文件,你不用單獨打開一個cmd窗口,也能夠讓input.txt的文本帶你的所有鍵盤輸入。缺點就是你要在提交之時將這句代碼註釋掉(或者刪掉);相信不少同學在提交的時候因爲忘了註釋這句而WA的。(在有的IDE上找源代碼文件所在目錄也不是很方便。)
下面就以經典的A+B問題爲例。如下是A+B問題的一個解法,其中input.txt是事先已經準備好的測試數據,並且和這個代碼文件放在同一目錄下(VC上是這樣,有的IDE可能要和.exe放到同一目錄):
#include <stdio.h>
int main()
{
int a,b;
freopen("input.txt", "r", stdin);
while( scanf("%d%d", &a, &b) == 2 )
{
printf( "%d\n", a+b );
}
return 0;
}
二.命令行環境下的————重定向。後面重點介紹。
使用重定向的代碼不需要做任何手腳(假設保存爲D:\OJ\aplusb.c):
#include <stdio.h>
int main()
{
int a,b;
while( scanf("%d%d", &a, &b) == 2 )
{
printf( "%d\n", a+b );
}
return 0;
}
下面就以編譯、測試位於D:\OJ目錄下的aplusb.c的步驟爲例:
- (要使用重定向你必須)先打開一個cmd窗口,並讓cmd窗口的當前目錄爲D:\OJ。
win7上只需打開D:\OJ文件夾,按住SHIFT鍵,在窗口的空白處右擊鼠標,點“在此處打開窗口”即可。
win xp上稍顯麻煩,
step1. WinKey+R彈出運行窗口,鍵入“cmd”回車,
彈出的cmd窗口顯示當前目錄是C:\Document and Setting\xxx(win7則是C:\Users\xxx);
step2. 再鍵入“D:”回車,跳轉到D盤;
step3. 再用cd命令跳轉到當前exe所在目錄(如果目錄名較長,可以從資源管理器的路徑欄上copy)。
win7上當然也可以這麼做,如下: - 編譯aplusb.c
假設你已經設置好了環境變量(如果你還沒有安裝配置命令行工具,點擊這裏):
gcc aplusb.c
將會有a.exe生成(如果想以其他名稱輸出加上-o選項,如gcc -o OutName.exe aplusb.c); - 測試a.exe
假設你已經準備好了一份測試數據,並以input.txt保存在相同目錄(D:\OJ)下(如果沒有,創建一個),則可以:
a.exe < input.txt
程序a.exe將會直接運行,並且以input.txt爲輸入;
這裏的<符號叫重定向輸入符(它右邊的文件將替換左邊程序或命令的標準輸入(cmd窗口輸入))
如input.txt內容如下:
1 2
3 4
5 6
7 8
9 10
100 200
200 400
400 800
20000 30000
5000000 6000000
70000000 80000000
運行gcc和a.exe後:
升級
一組整數,統計最大值、最小值、平均值
第一行一個32位整數n表示測試數據個數,接下來的n行每行一個非負32位整數
一行,最小值、最大值、平均值,空格分開
#include
#define INF 1000000000
int main() {
int x, n, num, sum = 0, min = INF, max = -INF;
scanf("%d", &num);
n = num;
while( n-- ) {
scanf("%d", &x);
sum += x;
if(x < min) min = x;
if(x > max) max = x;
}
printf("%d %d %.3lf\n", min, max, (double)sum/num );
return 0;
}
10
20
30
40
50
60
70
80
90
結果正確!
隨機數生成器
你可能對上面的一組測試數據不夠滿意,太少,太小,太弱?
下面寫一個能夠生成滿足題目輸入格式的隨機數生成器:
#include
#include
#include
int main()
{
int n;
srand( time(0) );
scanf( "%d", &n );
printf("%d\n", n);
while(n--) {
printf( "%u\n", rand() << 16 + rand() );
}
return 0;
}
編譯:
gcc rand_gen.c -o randgen.exe
運行:
solve.exe < rand_data.txt
管道
echo 10 | randgen.exe
“|”是管道符號,它將會把左邊的程序(或命令)的輸出重定向到右邊程序(或命令)的輸入.
管道可以連接使用;所以,我們可以這樣:
(.exe可以不用輸入)
過程是這樣的:
echo 10 ==10==> randgen.exe ==(臨時數據)===> solve.exe -> 屏幕輸出
查看一下代碼發現這裏有兩個問題:
i.無符號整數應該用unsigned int;
#include
#define INF 1000000000
int main()
{
unsigned x, n, num, min = INF, max = -INF; // ,s = 0;
double sum = 0;
scanf("%d", &num);
n = num;
while( n-- ) {
scanf("%d", &x);
sum += x;
if(x < min) min = x;
if(x > max) max = x;
}
printf("%u %u %.3lf\n", min, max, sum/num );
return 0;
}
附錄
http://technet.microsoft.com/zh-cn/library/cc772622(WS.10).aspx
Unix/Linux平臺,參考文章:
http://man.chinaunix.net/linux/mandrake/101/zh_cn/Command-Line.html/shell-pipes.html