使用Ctrl-D终止C++日期预订程序时错误输出提示信息的原因及修复方案
你遇到的问题核心在于循环时机判断和输入失败后的变量状态:
当按下Ctrl-D时,标准输入流cin会触发eofbit(文件结束标志)并进入失败状态,但你的main函数里while (cin)是在循环开始时检查流状态——如果上一次循环结束时流还是正常的,就会进入循环执行get(date)。此时get里的cin >> date.year会失败,但date变量的内容不会被清空,仍然保留着上一次输入的旧值。之后程序继续调用add函数,检查这个旧日期,发现它已经在预订列表里,就错误输出了“已被预订”的提示。
简单来说:输入结束后,程序误用上一次的旧日期执行了预订检查,导致了错误输出。
这里有几种简单且有效的修复方式,按推荐程度排序:
方案1:让get函数返回输入是否成功
修改get函数,让它在每次输入操作后检查cin的状态,一旦失败就返回false,提前终止循环,避免执行后续的add操作:
#include <iostream> #include <vector> using namespace std; struct Date_Type { int year; int month; int day; }; // 修改get函数,返回bool表示输入是否成功 bool get(Date_Type& date) { cout << "Mata in datum: "; // 逐个检查输入操作是否成功 if (!(cin >> date.year)) return false; cin.ignore(1); // 忽略分隔符'-' if (!(cin >> date.month)) return false; cin.ignore(1); if (!(cin >> date.day)) return false; return true; } void add(vector<Date_Type>& dates, Date_Type& date) { bool check_date = false; for (int i = 0; i < dates.size(); i++) { if (date.year == dates[i].year && date.month == dates[i].month && date.day == dates[i].day) { check_date = true; break; // 找到重复后直接跳出循环,优化性能 } } if (!check_date) { dates.push_back(date); cout << "Bokning gjord!" << endl; } else { cout << "Kan ej göra bokning, detta datum är redan bokat!" << endl; } } int main() { Date_Type date{}; vector<Date_Type> dates{}; // 只有当get成功时,才执行add while (get(date)) { add(dates, date); } return 0; }
这个方案逻辑清晰,把输入有效性检查封装在get函数里,主循环只处理有效的输入。另外我还在add函数里加了break,找到重复日期后就停止遍历,优化了一点性能。
方案2:在main里调用get后立即检查cin状态
如果你不想修改get函数的返回值,可以在main里调用get之后马上检查cin是否正常,失败就直接跳出循环:
int main() { Date_Type date{}; vector<Date_Type> dates{}; while (cin) { get(date); // 检查输入是否失败,失败则终止循环 if (!cin) break; add(dates, date); } return 0; }
这个方案改动最小,适合快速修复,但相比方案1,输入有效性的检查没有和输入逻辑封装在一起,代码稍显零散。
额外优化:处理输入分隔符的鲁棒性
你的cin.ignore(1)假设用户输入的分隔符是单个字符(比如'-'),但如果用户输入了多个分隔符(比如2021--04-15)或者其他字符,可能会导致后续输入错误。可以改成忽略所有非数字字符,直到遇到下一个数字或者流结束:
cin.ignore(numeric_limits<streamsize>::max(), '-');
不过这个需要包含<limits>头文件,属于额外的鲁棒性优化,不是解决当前问题必须的,但能让程序更健壮。
内容的提问来源于stack exchange,提问作者Cidrant

