C++巩固之输入输出流
笔者在同一个地方又一次跌倒了。来看看题目的要求吧。
【问题描述】
某校运动会的跳高比赛成绩保存在一个文本文件中,里面保存有多名参赛选手的号码、姓名和跳高成绩。读取文件,输出跳高冠军的号码、姓名和跳高成绩。输入输出格式参考样例。
【输入形式】
文件输入。比赛成绩文件"scores.txt"里保存有多行内容(行数不定,最少0行),每行保存一名参赛选手的号码、姓名和跳高成绩(中间以空格分隔)。每位选手的号码为一个由数字字符组成的4位连续字符串(中间不含空格和其他字符),姓名为一个只包含大小写英文字母的连续字符串(长度不超过20,中间不含空格和其他字符),成绩为一个开区间(0,3)内的带两位小数的实数(单位为米)。文件内容格式参考样例。
【输出形式】
屏幕输出。在提示语"The champion is: “之后输出跳高冠军的号码、姓名和跳高成绩(中间均以一个空格分隔,跳高成绩保留小数点后两位,成绩后加字符’m’)。如果比赛成绩文件不存在或文件内容为空,则输出提示语"Invalid file.”。输出内容格式参考样例。
【样例输入】(文件内容)
0310 Tom 1.72
0126 Jerry 1.81
0205 Jack 1.56
【样例输出】(屏幕输出)
The champion is: 0126 Jerry 1.81m
【评分标准】
共5组测试数据,全部正确得满分。
#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>
using namespace std;
/************ Begin ************/
/************* End *************/
int main()
{
char fileName[200] = "scores.txt";
string num, name;
double height;
bool bSuccess = GetChampionFromFile(fileName, &num, &name, &height);
if(bSuccess){
cout << fixed << setprecision(2);
cout << "The champion is: " << num << " " << name << " " << height << "m";
}
else{
cout << "Invalid file.";
}
return 0;
}
接下来,注意看是怎么错的。知道错在哪里很重要!!!
/** Begin **/
bool GetChampionFromFile(string fName, string * pNum,
string * pName, double * pHeight)
{
fstream inFile(fName, ios::in);
if(!inFile.is_open())
{
return false;
}
if(inFile.eof()) // 这个检验无效
return false;
string num, name;
double height = -1.00;
double temp = -1.00;
while(inFile.good())
{
inFile>>num>>name>>temp;
if(inFile.eof() && height == -1.00)
return false;
if(temp > height)
{
height = temp;
*pNum = num;
*pName = name;
*pHeight = height;
}
height = temp;
}
}
/*** End ***/
问题分析
1.试图用 if(inFile.eof()) return false;
在文件打开后立即判断是否为空。
inFile.eof()
仅在尝试读取到文本末尾后才会被设置为 true。直接打开空文件时 eofbit
初始状态为 0,因为尚未发生任何读取操作。
修正说明
- 使用
while (inFile >> num >> name >> *pHeight)
作为循环条件。 - 引入
hasValidData
变量,仅在成功读取至少一行数据时标记为 true。 - 处理无效数据。若文件中存在格式错误(如非数字字符),
inFile >> *pHeight
会失败,循环自动终止,函数返回 false。
bool GetChampionFromFile(string fName, string* pNum, string* pName, double* pHeight) {
ifstream inFile(fName);
if (!inFile.is_open())
{
return false; // 文件无法打开
}
string num, name;
double height = -1.0;
bool hasValidData = false;
while (inFile >> num >> name >> *pHeight) { // 直接在条件中读取数据
if (*pHeight > height) {
height = *pHeight;
*pNum = num;
*pName = name;
hasValidData = true; // 标记存在有效数据
}
}
// 检查是否成功读取至少一条数据
if (!hasValidData)
{
return false; // 文件为空或数据无效
}
*pHeight = height; // 确保返回最高成绩
return true;
}
eof()
具有滞后性:它只反映“上一次读取操作是否触发了文件末尾”,而非“文件是否为空”。
正确做法:通过实际读取操作(如 inFile >> var
)的返回值或流状态判断文件是否有效。
欢迎在评论区交流你的想法。