C++作业问题:ifstream成功打开文件但无法读取数据
问题描述
刚学习C++,作业中遇到如下问题:ifstream能成功打开与main.cpp同目录的PhoneBook.txt文件,但无法从中提取任何数据。已定义两个结构体:
Person:包含必填字符串Surname、Firstname,可选字符串MiddlenamePhoneNumber:包含必填int Countrynumber、int CityNumber、string phonenumber,可选附加号码
以下是相关代码与文件内容:
PhoneBook类代码
class PhoneBook { private: std::vector<std::pair<Person, PhoneNumber>> contact; public: PhoneBook(std::ifstream& ifs) { std::string sN, fN; std::optional<std::string> mN; int countryNum, cityNum; std::string phoneNum; std::optional<int> addNum; std::optional<std::string> aN; if (ifs.is_open()) { while (ifs >> sN >> fN >> mN.emplace() >> countryNum >> cityNum >> phoneNum >> addNum.emplace()) { if (mN.has_value()) if (mN.value() == "-") { mN = std::nullopt; } Person p(sN, fN, mN); if (addNum.has_value()) { if (aN.value() == "-") { addNum = std::nullopt; } else { addNum.emplace() = std::stoi(aN.value()); } } PhoneNumber ph1(countryNum, cityNum, phoneNum, addNum); contact.push_back(std::make_pair(p, ph1)); } } else { std::cout << "Error, couldn't open the file." << std::endl; } ifs.close(); } };
main函数代码
int main() { std::ifstream file("PhoneBook.txt"); PhoneBook book(file); std::cout << book; }
PhoneBook.txt内容
Ilin Petr Artemovich 7 17 4559767 - Zaitsev Zakhar Artemovich 125 44 4164751 - Dubinin Aleksei Mikhailovich 7 473 7449054 - Solovev Artur Mikhailovich 4 940 2556793 - Gerasimov Miroslav Stanislavovich 7 367 7508887 - Makeev Marat - 77 4521 8880876 999 Solovev Ivan Vladimirovich 7 273 5699819 5543 Egorov Savelii Stanislavovich 77 4521 8880876 99 Sokolov Arsenii - 93 163 1992257 16 Davydov Filipp Grigorevich 7 247 1377660 - Morozov Vladimir Mikhailovich 37 2290 5613649 - Orekhov Matvei Petrovich 81 8281 7420182 2 Titova Natalia - 93 163 1992257 9 Markelov Dmitrii Vadimovich 19 7576 5734416 2 Kozlovskii Artem Daniilovich 81 8281 7420182 1 Kuznetsov Kirill Kirillovich 7 017 8346563 - Mironova Margarita Aleksandrovna 7 273 5699819 5542 Kotov Vasilii Eliseevich 7 367 7508888 - Ivanov Daniil Maksimovich 7 366 7508887 - Aleksandrov Georgii - 493 7637 6114861 -
问题分析与修复
核心问题在于输入读取逻辑错误,导致循环直接终止,无法读取任何数据:
直接读取
optional的错误:
原代码用mN.emplace()和addNum.emplace()直接读取输入,但当遇到表示无值的-时,addNum.emplace()尝试将字符串-读取为int,会触发输入失败,导致整个while条件不成立,循环直接退出。未使用的变量导致未定义行为:
代码中aN变量从未被赋值,却在判断附加号码时调用aN.value(),会触发未定义行为。
修正后的PhoneBook构造函数
class PhoneBook { private: std::vector<std::pair<Person, PhoneNumber>> contact; public: PhoneBook(std::ifstream& ifs) { std::string sN, fN, mN_str; std::optional<std::string> mN; int countryNum, cityNum; std::string phoneNum; std::string addNum_str; std::optional<int> addNum; if (ifs.is_open()) { // 先读取所有字段到临时变量,避免类型不匹配导致输入失败 while (ifs >> sN >> fN >> mN_str >> countryNum >> cityNum >> phoneNum >> addNum_str) { // 处理中间名:非"-"则赋值,否则设为无值 mN = (mN_str != "-") ? mN_str : std::nullopt; Person p(sN, fN, mN); // 处理附加号码:非"-"则尝试转换为int,失败则设为无值 if (addNum_str != "-") { try { addNum = std::stoi(addNum_str); } catch(const std::exception&) { addNum = std::nullopt; } } else { addNum = std::nullopt; } PhoneNumber ph1(countryNum, cityNum, phoneNum, addNum); contact.push_back(std::make_pair(p, ph1)); // 重置可选值,避免下一次循环残留上一次数据 mN.reset(); addNum.reset(); } } else { std::cout << "Error, couldn't open the file." << std::endl; } ifs.close(); } // 声明友元,确保operator<<能访问私有成员contact friend std::ostream& operator<<(std::ostream& os, const PhoneBook& book); }; // 示例operator<<实现(需确保Person和PhoneNumber的operator<<已正确定义) std::ostream& operator<<(std::ostream& os, const PhoneBook& book) { for (const auto& entry : book.contact) { os << entry.first << " | " << entry.second << "\n"; } return os; }
关键修正点
- 用临时字符串读取中间名和附加号码,避免直接读取
int导致输入失败 - 通过判断临时字符串是否为
-,决定是否给optional赋值 - 移除无用的
aN变量,消除未定义行为 - 添加
try-catch处理附加号码转换失败的情况 - 每次循环后重置
optional,防止残留上一次的值 - 补充友元声明,确保
operator<<能访问私有成员contact
内容的提问来源于stack exchange,提问作者Zetton
相关产品推荐
相关产品推荐

