You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++作业问题:ifstream成功打开文件但无法读取数据

问题描述

刚学习C++,作业中遇到如下问题:ifstream能成功打开与main.cpp同目录的PhoneBook.txt文件,但无法从中提取任何数据。已定义两个结构体:

  • Person:包含必填字符串Surname、Firstname,可选字符串Middlename
  • PhoneNumber:包含必填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 -
问题分析与修复

核心问题在于输入读取逻辑错误,导致循环直接终止,无法读取任何数据:

  1. 直接读取optional的错误:
    原代码用mN.emplace()和addNum.emplace()直接读取输入,但当遇到表示无值的-时,addNum.emplace()尝试将字符串-读取为int,会触发输入失败,导致整个while条件不成立,循环直接退出。

  2. 未使用的变量导致未定义行为:
    代码中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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 14:30:53