我的PAT系列文章更新重心已移至Github,歡迎來看PAT題解的小伙伴請(qǐng)到Github Pages瀏覽最新內(nèi)容。此處文章目前已更新至與Github Pages同步。歡迎star我的repo。
題目
本題的基本要求非常簡(jiǎn)單:給定 個(gè)實(shí)數(shù),計(jì)算它們的平均值。但復(fù)雜的是有些輸入數(shù)據(jù)可能是非法的。一個(gè)“合法”的輸入是 [
]
區(qū)間內(nèi)的實(shí)數(shù),并且最多精確到小數(shù)點(diǎn)后 2 位。當(dāng)你計(jì)算平均值的時(shí)候,不能把那些非法的數(shù)據(jù)算在內(nèi)。
輸入格式:
輸入第一行給出正整數(shù) (
)。隨后一行給出
個(gè)實(shí)數(shù),數(shù)字間以一個(gè)空格分隔。
輸出格式:
對(duì)每個(gè)非法輸入,在一行中輸出 ERROR: X is not a legal number,其中 X 是輸入。最后在一行中輸出結(jié)果:The average of K numbers is Y,其中 K 是合法輸入的個(gè)數(shù),Y 是它們的平均值,精確到小數(shù)點(diǎn)后 2
位。如果平均值無法計(jì)算,則用 Undefined 替換 Y。如果 K 為 1,則輸出 The average of 1 number is Y。
輸入樣例 1:
7
5 -3.2 aaa 9999 2.3.4 7.123 2.35
輸出樣例 1:
ERROR: aaa is not a legal number
ERROR: 9999 is not a legal number
ERROR: 2.3.4 is not a legal number
ERROR: 7.123 is not a legal number
The average of 3 numbers is 1.38
輸入樣例 2:
2
aaa -9999
輸出樣例 2:
ERROR: aaa is not a legal number
ERROR: -9999 is not a legal number
The average of 0 numbers is Undefined
思路
先說說輸入: 我們不清楚題目會(huì)給出多長(zhǎng)的非法輸入,因此為了防止溢出,我們應(yīng)該選擇一個(gè)安全的方式應(yīng)對(duì)這種情況。
我的方法是先確定合法數(shù)字的最長(zhǎng)長(zhǎng)度:8個(gè)字符,那么我們每次就先只讀8個(gè)字符。如果輸入流(stdin)中的下一個(gè)字符不是空白字符,那么這個(gè)數(shù)就絕對(duì)非法;如果是空白字符的話,再繼續(xù)討論接下來的問題。
(這個(gè)問題幾乎網(wǎng)上所有AC的方法都是用的一個(gè)大數(shù)組來讀取,應(yīng)該是PAT對(duì)這一點(diǎn)沒有嚴(yán)格檢查(要是有上千字符的輸入就不行了)。我只是出于健壯性考慮,照顧到了這一點(diǎn))
(通過率0.19的題我一次AC了,先讓我激動(dòng)一會(huì)兒 \(≧▽≦)/ )
代碼實(shí)現(xiàn)
- 讀取8個(gè)字符,使用了
scanf("%8s", str),就是讀到空白字符或者8個(gè)字符。 - 判斷是否是浮點(diǎn),使用了函數(shù)
strtod(const char *, char **),這個(gè)函數(shù)的第二個(gè)參數(shù)是一個(gè)指針的地址,用來使該指針指向未用于轉(zhuǎn)換的第一個(gè)字符,我們可以根據(jù)這個(gè)指針是否為NULL來判斷這個(gè)字符串是否為浮點(diǎn)。
(e.g. 如第一個(gè)參數(shù)傳入字符串2.3.4,第二個(gè)參數(shù)這個(gè)指針會(huì)指向第二個(gè)小數(shù)點(diǎn)) - 精度,找到小數(shù)點(diǎn)(有的話)的位置,看它距字符串結(jié)尾有幾個(gè)字符就好了,不能大于3個(gè)。
P.S. 在網(wǎng)上看到了結(jié)合使用sscanf和sprintf的方法,相當(dāng)?shù)那擅?。忘記了在哪里,讀者可自行查找,或嘗試自己去實(shí)現(xiàn)。
代碼
最新代碼@github,歡迎交流
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int count = 0, N;
double f, sum = 0;
/* Maxium scenario: -1000.00. So just need to read 8 chars(+ '\0' = 9) */
char s[9], *pEnd, *pDot, c;
scanf("%d", &N);
for(int i = 0; i < N; i++)
{
scanf("%8s", s); /* Just read up to 8 chars */
c = ungetc(getchar(), stdin); /* Read next char and push back */
f = strtod(s, &pEnd); /* pEnd -> converted floating number */
pDot = strchr(s, '.'); /* pDot -> (first) decimal point */
if(!isspace(c) /* string too long */
|| *pEnd /* not floating number */
|| (f > 1000 || f < -1000) /* out of range */
|| (pDot && pDot - s < strlen(s) - 3)) /* precision too high */
{
printf("ERROR: %s", s);
/* this can avoid overflow (we don't know how long input is) */
while(!isspace(c = getchar())) putchar(c);
printf(" is not a legal number\n");
}
else /* legel number */
{
count++;
sum += f;
}
}
if(count == 0) printf("The average of 0 numbers is Undefined\n");
if(count == 1) printf("The average of 1 number is %.2lf", sum);
if(count >= 2) printf("The average of %d numbers is %.2lf", count, sum / count);
return 0;
}