匯總一下在算法考試中常見的輸入格式及處理方法,以防止出現(xiàn)明明算法是會的但由于輸入問題處理不好導(dǎo)致題目沒有答出,我就栽倒在這個問題上過。
一、幾個常用的輸入函數(shù)的異同
1. scanf()
需要包含頭文件stdio.h。
scanf函數(shù)的返回值就是讀入的變量的個數(shù)。
#include <stdio.h>
int main() {
int a, b;
int m = scanf("%d %d", &a, &b);
printf("a = %d, b = %d, m = %d", a, b, m);
return 0;
}
輸入輸出結(jié)果如下。

在這里,scanf函數(shù)規(guī)定了要輸入兩個變量,則一定要輸完兩個變量才可以進行下去,如果沒輸完兩個變量,不管中間是按回車還是空格,都不會繼續(xù)執(zhí)行程序而是已知等待輸入。這說明,scanf函數(shù)并不把回車和空格判定成一個輸入。


scanf遇到空格、tab、回車都會判定結(jié)束。例如,如果只要求輸入一個字符串但實際上輸入了被空格分開的兩個字符串,則只讀入第一個。
#include <stdio.h>
int main() {
char a[10];
scanf("%s", a);
printf("%s", a);
return 0;
}

scanf也可以用來輸入多個字符串,每個字符串之間用空格分開。
#include <stdio.h>
int main() {
char a[10], b[10];
scanf("%s %s", a, b);
printf("%s\n%s", a, b);
}

與輸入其他類型的數(shù)據(jù)時同樣,scanf必須讀夠兩個輸入才會繼續(xù)運行,兩個輸入之間的空格和回車都不算。
2. cin >>
需要包括頭文件iostream和命名空間std。
#include <iostream>
using namespace std;
其他各項特點基本與scanf相同,但還是有一些細(xì)微的區(qū)別??梢詤⒖歼@篇文章。由于從時間效率上,scanf比cin要快很多,所以我鄭重在寫算法題時使用scanf,常常有意想不到的效果。
3. c++中其他常用輸入函數(shù)

補充:無回車不回顯的輸入方式
_getch()函數(shù)是一個不回顯函數(shù),當(dāng)用戶按下某個字符時,函數(shù)自動讀取,無需按回車,有的C語言命令行程序會用到此函數(shù)做小游戲,但是這個函數(shù)并非標(biāo)準(zhǔn)函數(shù),要注意移植性!需要包括頭文件conio.h。
二、常見輸入輸出情況匯總
1. 預(yù)先告知有N個輸入塊,接下來N行是這N個輸入塊的內(nèi)容
計算A+B的值
輸入描述:每一行整數(shù)N,接下來有N行輸入,每行輸入兩個整型數(shù)字A和B,由空格分開,每組數(shù)字占一行。
輸出描述:每個例子輸出A+B單獨作為一行。
輸入樣例:
2
1 1
4 4
輸出樣例:
2
8
這是最簡單的情況,沒啥好說的,直接上代碼。
c語法:
scanf("%d",&n) ;
for( i=0 ; i<n ; i++ ) {
scanf("%d %d",&a, &b);
printf(“%d\n”,a+b);
}
c++語法:
cin >> n;
for( i=0 ; i<n ; i++ ) {
cin >> a >> b;
cout << a+b << endl;
}
2. 輸入時不說明有多少個輸入塊,但以EOF結(jié)尾
計算A+B的值
輸入描述:每一行輸入兩個整數(shù)A和B,由空格分開。
輸出描述:每個例子輸出A+B單獨作為一行。
輸入樣例:
1 1
2 2
輸出樣例:
2
4
補充:什么是文件結(jié)束符EOF
EOF是End Of File的縮寫,是一個預(yù)定義的常數(shù),值為-1。通常在文本的最后存在此字符表示資料結(jié)束。
以EOF作為文件結(jié)束標(biāo)志的文件,必須是文本文件。因為在文本文件中,數(shù)據(jù)都是以字符的ASCII代碼值的形式存放。ASCII代碼值的范圍是0~255,不可能出現(xiàn)-1,因此可以用EOF作為文件結(jié)束標(biāo)志。
c語法:
while (scanf("%d %d", &a, &b) != EOF) {
...
}
我寫了這樣一個程序。
#include <stdio.h>
int main() {
int a, b;
while (scanf("%d %d", &a, &b) != EOF) {
printf("%d", a + b);
}
}
結(jié)果如下。如果你是從控制臺輸入的話,每輸入兩個數(shù)字,按一下回車,就會輸出一個結(jié)果。但問題是,程序會已知循環(huán)下去,不知道什么時候判定成輸入結(jié)束。

如果我這樣輸入。一下子輸入好幾組數(shù)字,不使用回車,則每次循環(huán)會順序往后讀入兩個輸入,然后打印在屏幕上。但依舊不知什么時候判定成結(jié)束輸入。

這是因為文件結(jié)束符是存在于文件輸入的情況。如果你是控制臺輸入,沒有手動輸入文件控制符,自然不可能結(jié)束循環(huán)。
然而,ACM競賽平臺通常是從文本中進行數(shù)據(jù)輸入的,因此會使用文件結(jié)束符EOF作為結(jié)束標(biāo)志。因此在這類沒有限定結(jié)束標(biāo)志的問題中,直接判斷是否讀到文件結(jié)束符EOF就可以了。
c++語法:
while (cin >> a >> b) {
...
}
3. 輸入時需要處理換行符
我曾經(jīng)栽倒在這樣的題目上過,明明算法很簡單,但處理輸入處理了半個多鐘頭。下面舉個例子。
鏈表合并問題
輸入描述:先輸入一個非負(fù)數(shù)n,表示有n個鏈表。接下來輸入n行,每行有若干個數(shù)字,中間用空格隔開,表示每一個鏈表。
輸出描述:輸出合并后的鏈表。
使用getchar()判斷輸入的字符是不是換行符'\n'。代碼如下,只處理了輸入問題,沒有實現(xiàn)該題目的具體邏輯。
#include <stdio.h>
#include <vector>
using namespace std;
int main() {
int N;
scanf("%d", &N);
vector<vector<int>> linklists;
for (int i = 0; i < N; i++) {
vector<int> llist;
int num;
do {
scanf("%d", &num);
llist.push_back(num);
} while (getchar() != '\n');
linklists.push_back(llist);
}
//打印上面輸入的內(nèi)容
for (auto& a : linklists)
{
for (auto b : a)
printf("%d ", b);
printf("\n");
}
return 0;
}
這篇文章寫起來不易,如果它對你有幫助的話,麻煩給個贊吧??!