【问题标题】:Read from a file to three parallel array从文件读取到三个并行数组
【发布时间】:2018-04-13 23:39:21
【问题描述】:

作为我作业的一部分,我需要打开一个文件,然后将信息读入 3 个数组。这些信息分为 3 个不同的列,第一个是国家代码名称(是字符串),第二个是人口(是 int),第三个是国家的全名。以下是文件几行的示例:

  • AU 20090437 澳大利亚
  • BR 186112794 巴西
  • BU 7262675 保加利亚
  • 加拿大 32805041 加拿大
  • CN 1306313812 中国
  • DO 8950034 多米尼加共和国

到目前为止我有:

void readCntrData(string [], int [], string[], int &size, const int maxSize);

int main()
{
    const int COUNTRIES = 200;
    // maximum size of arrays
    int size = 0;
    string cntrCodes[COUNTRIES];
    int cntrPopulation[COUNTRIES];
    string cntrNames[COUNTRIES];

    string inputFileName = "countries.txt";
    ifstream inputFile;

    inputFile.open(inputFileName.c_str());
    if (inputFile.fail())
    {
        cout << "\n\tPlease check the name of the input file and \n\ttry again later!\n";
        exit(EXIT_FAILURE);
    }
    int index = 0;
    while (index < COUNTRIES && inputFile >> cntrCodes[index] >> cntrPopulation[index] >> cntrNames[index] ) {

        index++;
    }

    size = index;
    if (size == COUNTRIES && !inputFile.eof()){
        cout << "\n\tThe input file  \"" << inputFileName <<
        "\"is too big: \n\tit has more than " << COUNTRIES << " items!\n";
        exit(EXIT_FAILURE);
    }
    inputFile.close();
}

这里的问题很少有国家有两个部分名称,我的代码在国家名称有两个部分的地方中断。我不知道如何忽略那里的空间并阅读整个名称。

感谢任何反馈。

【问题讨论】:

  • 考虑一个包含三段数据的结构数组,而不是三个并行数组。让一切保持同步变得更加容易。
  • 不要使用数组。不要使用“并行数组”。使用结构或类的向量。
  • 幸运的是,多词标记位于行尾。你可以file &gt;&gt; token 1 &gt;&gt; token2 &amp;&amp; getline(file, token3)
  • while (index &lt; COUNTRIES &amp;&amp; inputFile &gt;&gt; cntrCodes[index] &gt;&gt; cntrPopulation[index] &gt;&gt; cntrNames[index] ) 干得好
  • @NeilButterworth 不幸的是我还没有了解结构和类。谢谢你的建议

标签: c++ arrays file


【解决方案1】:

只是稍微清理一下代码......

  • 您在问题中提出的主要问题已由 cmets 中的 user4581301 解决:总而言之,使用 getline 读取国家代码将处理一个或多个空格分隔的单词
  • 从 C++11 开始,我们已经能够使用 ifstream 构造函数打开在 std::string 中传递的文件名,并且在 if/@987654327 中构造 ifstream 通常很方便@ 构造,然后处理成功打开和尝试打开失败的情况
  • 无论如何都没有必要明确关闭超出范围的ifstreams
  • 最好将错误消息发送到std::cerr,因此如果有人运行您的程序执行“theprogram > theprogram.output”之类的操作,他们仍会在终端中看到错误消息
  • 实际上不需要单独的 indexsize 变量,像 num_countries 这样的名称是更好、更有意义的名称
  • 检查 EOF 有点像黑魔法 - 我不建议您像以前那样使用 inputFile.eof(),因为如果最后读取的国家/地区后跟文件中的空行,您就不会结束-of-file 即使此后它“逻辑上”是空的;当某人在编辑器中创建/更新文件时,很容易不注意到文件末尾的空行;检查是否有另一个非空白字符是一种更可靠的方法
  • 如今int 的常见大小是 32 位,它可以处理高达几十亿的数字(当签名时,或者对于 unsigned int 来说超过 40 亿);中国的人口数量太接近了,让人感到不舒服——如果你想以一种在 20 或 50 年后仍然可以工作的方式编写代码,那么最好考虑一下这些类型是否仍然足够大来存储这些值;来自&lt;cstdint&gt;int64_t 是更好的选择。

修改后的代码:

int main()
{
    const int COUNTRIES = 200;

    string cntrCodes[COUNTRIES];
    int64_t cntrPopulation[COUNTRIES];
    string cntrNames[COUNTRIES];

    string inputFileName = "countries.txt";
    if (std::ifstream inputFile{inputFileName})
    {
        int num_countries = 0;
        while (num_countries < COUNTRIES &&
               inputFile >> cntrCodes[num_countries] >> cntrPopulation[num_countries] &&
               getline(std::cin, cntrNames[num_countries]))
            ++num_countries;

        // will see if we can read another character (remember >> skips
        // whitespace by default), rather than check inputFile.eof()
        // which may not be true if there're any extra empty lines after
        // the data...
        char character;
        if (num_countries == COUNTRIES && inputFile >> character)
        {
            std::cerr << "\n\tThe input file  \"" << inputFileName <<
        "\"is too big: \n\tit has more than " << COUNTRIES << " items!\n";
            exit(EXIT_FAILURE);
        }

        // any extra code to actually use the country data goes here...
    }
    else
    {
        std::cerr << "\n\tPlease check the name of the input file and \n\ttry again later!\n";
        exit(EXIT_FAILURE);
    }
}

【讨论】:

  • 感谢@Tony Delroy。非常翔实的回应,我很感激。
【解决方案2】:

对于每一行的最后输入,您可以使用 getline 读取所有内容,直到遇到 Enter 键。

你可以试试这个:

while (index < COUNTRIES && inputFile >> cntrCodes[index] >> cntrPopulation[index] ) {
    getline (inputFile, cntrNames[index]);
    index++;
}

【讨论】:

  • 重要的是条件取决于对getline 的调用是否成功 - 否则如果缺少国家/地区,您将不会注意到并将其留空。要解决这个问题,您应该将&amp;&amp; getline(inputFile, cntrNames[index]) 附加到条件(而不是在语句块内调用getline 循环控制)。
猜你喜欢
  • 1970-01-01
  • 2017-09-27
  • 1970-01-01
  • 1970-01-01
  • 2016-11-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多