【问题标题】:Summing comma separated ints from a text file and then storing to an array in C++从文本文件中求和逗号分隔的整数,然后存储到 C++ 中的数组中
【发布时间】:2021-08-10 17:39:22
【问题描述】:

我的任务是从文本文件中读取 3 行,每行 5 个逗号分隔的值,对每一列求和,然后将结果存储在一个名为 bins 的数组中。我正在努力从文本文件中读取整数,因为它们是逗号分隔的。我首先需要澄清如何只读取整数。

我的下一个想法是将文件中的整数存储到一个名为“calc”的数组中,并使用每个元素的索引来汇总值。然后我会将这些结果存储到“bins”数组中。

这是我尝试读取逗号分隔整数的一些代码,但我似乎无法让它工作。

int a,b,c,d,e,f,g,h,i,j,k,l,m,n,o;
int calc[15] = {a,b,c,d,e,f,g,h,i,j,k,l,m,n,o};

ifstream myfile;
myfile.open("values.txt");

for(int i = 0; i <= 15; i++)
{
    myfile >> calc[i];

    myfile.close();
    a = calc[0];
    b = calc[1];
    c = calc[2];
    d = calc[3];
    e = calc[4];
    f = calc[5];
    g = calc[6];
    h = calc[7];
    i = calc[8];
    j = calc[9];
    k = calc[10];
    l = calc[11];
    m = calc[12];
    n = calc[13];
    o = calc[14];

    cout << calc[i] << endl;
}

我对使用代码真的很陌生,但我不太了解如何以这种方式使用值。这是一项简单的任务,但我似乎无法用代码实现它。

【问题讨论】:

  • i &lt;= 15 off-by-one error 在这里。
  • int calc[15] = {a,b,c,d,e,f,g,h,i,j,k,l,m,n,o}; 看起来有点可疑。为什么不int calc[15];int calc[15] = { };。您所做的是用 15 个未初始化变量 a ... o 初始化 15 个数组元素。恐怕这会使数组仍然像以前一样“未初始化”。
  • @Scheff 它们在全局范围内,因此它们是默认初始化的,即 0。但否则代码有异味。有int calc[15] = {};就够了
  • @Swift-FridayPie 它们在全球范围内不确定。我想这里有一些东西遗漏了。 for 之类的语句不能在全局范围内使用。 (它们可能只出现在任何类型的函数体中。)
  • edit 并提供minimal reproducible example。否则,它不会持续很长时间,直到有人告诉你这只是不按原样编译......;-)

标签: c++ arrays txt


【解决方案1】:

我对使用代码真的很陌生,而且我 [原文如此] 不太了解如何以这种方式使用值。

好的,我有几个提示给你:

①分离任务

您在以提供的格式解析输入时遇到了麻烦,处理逗号。解析提供的输入文件是一个与实际工作完全不同的问题,即对列求和。分别写在代码里。

一般你应该将“实际工作”隔离在它自己的函数中,让它接受参数作为输入,并将结果作为函数返回值返回。 输入输出是分开写的。

通过调用带有内置测试用例的“工作”函数,您可以获得自动测试的额外好处。在这种情况下,它允许您推迟解析。您现在只需传递测试数据,让“工作”部分工作,然后您可以返回解析输入。然后,当您确实需要帮助时,它将专门用于“解析逗号分隔值”,与您为什么需要它们无关。

②要处理一组值,您使用数组

这意味着下标或迭代,使用循环(或库算法)来获取您想要做的事情,编写一次,并将其应用于数组中的每个值。

给定数组 inputsum,您可以使用如下代码将当前行 (input) 累加到正在运行的 sum 中:

for (size_t i = 0;  i < COLS;  ++i) {
    sum[i] += input[i];
}

整体程序草图

open the file
repeat three times:
    read a row of input
    accumulate the sum with the new input
print the results

请注意,如第一个主题中所述,读取一行累加总和是单独的功能和单独的子任务来计算。这称为问题的自上而下分解

最好使用参数作为函数的输入和返回值,但是对于这个简单的任务,我将只使用一个全局变量。通过/返回可能比您正在学习的任务更难!请注意,这是不现实的,因为在实际代码中您不想使用这样的全局变量。但是,您可以将其变成一个“对象”,稍后您将了解它。

#include <fstream>
constexpr size_t ROWS = 3;
constexpr size_t COLS = 5;

int input[COLS];
int sum[COLS];

std::ifstream infile;

int main()
{
    infile.open("values.txt");
     // todo:  check for success and feedback to the user if failed
    // skipped:  zero out the sum array.  Global variable start at 0,
    //           but more generally, you would need to initialize this.
    for (size_t row= 0;  row < ROWS;  ++row) {
        read_row();
        sum_row();
    }
    print_results();
}

sum_row 函数就是您之前看到的。

请注意,通过自上而下的分解,您可以剔除稍后将处理的部分。特别是,你可以让read_row首先返回硬编码的结果,或者从不同的格式读取,这样你就可以测试整个程序。然后,返回并让该部分真正发挥作用。

自顶向下分解对于任何类型的编程项目都至关重要。

【讨论】:

    【解决方案2】:

    糟糕...你的大部分代码都没用,剩下的也不是很好。

    编写好的程序不是一个接一个地添加 C++ 指令的问题。您必须首先设计程序的整体结构。

    这里有一个包含 5 行逗号分隔值的输入文件,并且想要计算一个包含列总和的数组(大小为 5)。

    从高处放手

    open the file
    loop over the lines
        loop 5 times:
            read a field up to a comma (or end of the line)
            decode that field into an int value
            sum that value into an array
    close the file
    

    好的,为了能够将值相加成一个数组,我们必须在循环之前定义数组并将其元素初始化为 0。

    好的,C++ 提供std::ifstream 来读取文件,std::getline 来读取流直到分隔符(默认为换行符),std::istringstream 来读取字符串的内容作为输入流和std::stoi解码表示 int 值的字符串。

    一旦完成,但仅限于:

    • 程序结构设计清晰
    • 标准库中的所需工具已确定

    可以坐在键盘前开始编码。

    顺便说一句,这个程序永远不需要声明 15 个变量 ao 也不需要 15 个整数的数组:只有 int bins[5]...

    可能是(为简洁起见省略了测试):

    int bins[5] = {0};  // initializing the first value is enough, others will be 0
    std::ifstream in("values.txt");
    std::string line;
    while (std::getline(in, line)) {
        // std::cout << line << '\n';  // uncomment for debug
        std::stringstream ss(line);
        for(int& val: bins) {    // directly loop over the bins array
            std::string field;
            std::getline(ss, field, ',');
            val += std::atoi(field.c_str());
        }
    }
    

    当然,对于专业级(或简单的健壮)程序,每个输入操作之后都应该对流进行测试...

    【讨论】:

      【解决方案3】:

      您可以使用string 库中的std::getline 函数来获取每个逗号分隔的整数。

      std::ifstream myfile("values.txt");
      
      for(int i = 0; i < 15; i++)
      {
          std::string integer_as_string;
          std::getline(myfile, integer_as_string, ',');
          calc[i] = std::stoi(integer_as_string);
      }
      
      myfile.close();
      

      这里我们指定getline 函数将读取输入中的 字符,直到找到, 字符。此字符串分配给integer_as_string 变量,然后将其转换为整数并分配给数组。

      还要注意i &lt;= 15 将导致未定义的行为。您可以在此处进一步阅读:Wikipediamyfile.close() 函数设置在 for 循环中。这意味着在每次迭代中,您都将关闭文件。这不是必需的。我想你要找的是这样的东西。

      std::ifstream myfile("values.txt");
      
      for(int i = 0; i < 15; i++)
      {
          std::string integer_as_string;
          std::getline(myfile, integer_as_string, ',');
          calc[i] = std::stoi(integer_as_string);
      
          std::cout << calc[i] << std::endl;
      }
      
      myfile.close();
      
      a = calc[0];
      b = calc[1];
      c = calc[2];
      d = calc[3];
      e = calc[4];
      f = calc[5];
      g = calc[6];
      h = calc[7];
      i = calc[8];
      j = calc[9];
      k = calc[10];
      l = calc[11];
      m = calc[12];
      n = calc[13];
      o = calc[14];
      

      参考:
      std::stoi
      Why is "using namespace std;" considered bad practice?

      【讨论】:

      • @Scheff 对不起,我错过了拼写。感谢您指出!
      • 使用逗号作为分隔符不会在换行符处停止。至少,每行中的最后一个值以及何时停止读取行将是一个问题。
      【解决方案4】:

      首先,您的数组有索引从 0 到 14 的元素,因此 for(int i = 0; i &lt;= 15; i++) 应该是 for(int i = 0; i &lt; 15; i++)

      循环本身可能会受益于错误检查。如果文件包含的值少于 15 个怎么办?

      for(int i = 0; i <= 15; i++)
      {
          // you want check status of myfile here. 
          
      }
      

      myfile &gt;&gt; calc[i] 不适用于逗号,除非您将逗号添加到该流的分隔符类中。尽管可以做到这一点,但更改有点大,可以使用getline (see answers here for examples) 代替指定分隔符。

      如果您希望命名变量引用数组元素,您可以将它们引用并structurally bind 将它们引用到数组(或其他类似元组的数据结构,例如 struct 等),前提是您可以访问 C++ 17

      int calc[15] = {};
      auto& [a,b,c,d,e,f,g,h,i,j,k,l,m,n,o] = calc;
      

      a 将成为对calc[0] 的引用,bcalc[1] 等等。

      【讨论】:

      • 他不应该使用a,b,c 等作为单独的变量。他的部分问题是了解如何使用数组。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多