【问题标题】:Reading in both doubles and words and performing actions based on what is read阅读双打和单词,并根据所读内容执行操作
【发布时间】:2014-01-29 17:49:39
【问题描述】:

我正在编写一个程序,它接收输入并将其格式化为“名称分数”的分数。 这是需要做的事情“这是Moonglow的格式。

  • 文本文件由单词组成。如果一个词是一个数字,那么这就是学生在一个问题上的分数,所以你将它添加到学生的考试分数中。

  • 如果单词不是数字,而是单词“NAME”,那么下一个单词是学生的名字(Moonglow 只使用名字——姓氏是公司的和非个人的)。

  • 如果单词是“AVERAGE”,那么您将开始读取数字,直到您读取到一个不是数字的单词(或者是文件的结尾)。您将所有这些数字平均并将其添加到分数中。由于 Moonglow 有点杂乱无章,因此有时数字不会跟随“AVERAGE”。在这种情况下,您忽略“平均”。 "

我的问题是我不知何故进入了一个无限循环,并且花了几个小时试图解决这个问题。这是一个非常简单的程序,我似乎无法让它工作!

#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <stdlib.h>
using namespace std;

int main()
{
    string s, name = "test";
    string buffer;
    double qScore, eScore, totalExam = 0, grade = 0, numExam = 0, finalGrade, avg = 0;
    while (!cin.eof())
    {
        if (cin >> qScore)
        {
            if (cin.fail())
            {
                cin.clear();
            }

            else
            {
                grade += qScore;
            }
        }
        else if (cin >> s)
        {
            if (s == "NAME")
            {
                cin >> s;
                s = name;
            }
            else if (s == "AVERAGE")
            {
                while (cin >> eScore)
                {
                    numExam++;
                    totalExam += eScore;

                }
                cin.clear();
            }
        }
    }

    if (numExam == 0)
    {
        avg = 0;
    }
    else
    {
        avg = (totalExam / numExam);
    }
    finalGrade = avg + grade;
    cout << name << " " << finalGrade << endl;
    return 0;

}
// end of main

【问题讨论】:

  • 我应该用 while (cin >> qScore || cin >> s) 替换它吗?
  • 将其替换为while (cin &gt;&gt; qScore &amp;&amp; cin &gt;&gt; s)。你还可以做更多的事情来修复这个程序。这只是一个。
  • 我看到我的代码的另一个严重错误是没有任何内容被读入“名称”。无论我执行什么,输出中都没有给出名称。
  • 1:2: 是输入的一部分吗?

标签: c++ string cout cin stringstream


【解决方案1】:

我不会为您编写代码(因为这显然是一个家庭作业问题),但我会提供一些建议,说明我将如何以完全不同的方式执行此操作。希望这个伪代码有所帮助。

编辑:我错过了 AVERAGE 的逻辑以及分数应该如何工作,我正在做一些更正。 (注意,通过这些更改,添加新状态可能会更好。我会考虑 Normal、Name、BeginAverage、Average、EndAverage。但这取决于你。

1) 定义这些状态(也许使用枚举):

  • 普通(这个可能有更好的名字)
  • 姓名
  • 平均

2)您想读取一个“令牌”并使用以下规则进行转换。请注意,在这种情况下,标记将是一个字符串,由空格分隔(例如“NAME”、“AVERAGE”、“Bob”、“11”、“23”)。

  • 如果状态为正常(这也是初始状态)
    • 如果令牌是“NAME”,则转到状态名称
    • 如果令牌为“AVERAGE”,则转到状态“Average”
    • 如果标记以“0”、“1”、“2”、...“9”这些字符之一开头,请将其转换为双精度并添加到您的分数中
  • 如果状态是名称
    • 将令牌复制到您的“名称”变量中,转换回正常状态
  • 如果状态为平均
    • 如果您得到一个数字,请将其添加到临时计数中并增加一个计数器
    • 如果您得到的字符串不是“NAME”、“AVERAGE”或数字,请返回正常状态
    • 如果您获得“NAME”,请转到名称状态
    • 在进入此状态之前,您需要重置您的临时计数/计数器以计算平均值
    • 在离开此状态之前,计算平均值并将其添加到总分中

3) 为了处理输入,首先将everything读入一个字符串变量。然后您可以在需要时使用stringstreams 转换为双精度。只需阅读我描述的所有字符串(令牌)并按上述方法处理它们,直到达到 EOL。

“代码”:

while (cin >> s)
{
    if (state == state_normal)
    {
        if (s == "NAME") { state = state_name; }
        else if (s == "AVERAGE")
        {
            state = state_average;
            // You are starting a new average, initialize these variables to 0
            scoresToAverage = 0;
            numberOfScores = 0;
        }
        else if (isNumber(s))
        {
            number = convertToNumber(s);
            score += number;
        }
    }
    if (state == state_name)
    {
        name = s;
        state = state_normal;
    }
    if (state == state_average)
    {
        bool calculateAverage = false;
        if (s == "NAME")
        {
             state = state_name;
             calculateAverage = true;
        }
        else if (s == "AVERAGE")
        {
             state = state_average;
             calculateAverage = true;
        }
        else if (isNumber(s))
        {
            number = convertToNumber(s);
            scoresToAverage += number;
            numberOfScores++;
        }
        else
        {
            state = state_normal;
            calculateAverage = true;
        }

        // If you are DONE averaging, calculate the average and add it to the total
        if (calculateAverage)
        {
            if (numberOfScores > 0)
            {
                score += (scoresToAverage / numberOfScores);
            }
            scoresToAverage = 0;
            numberOfScores = 0;
        }
    }
}

// done reading input, just print!

isNumber 接受一个字符串,并且可以检查第一个字符是否为数字('0'、'1'、...)。它可能会更漂亮,并查看每个字符的数字/小数。

convertToNumber 接受一个字符串并转换为双精度。可以使用stringstreams 进行转换,也可以只使用旧的atoi

【讨论】:

  • 到目前为止这很有帮助。就一个问题。对州使用枚举是什么意思?
  • 假设你不知道enum 是什么,cprogramming.com/tutorial/enum.html 所以你可以创建一个新的enum 类型,其中每个可能的值都是不同的状态。或者,您可以使用int 并定义constants,因此0 是第一个状态,1 是第二个状态,2 是第三个状态。这就是(某种程度上)enum 正在为你做的事情。
  • 我查找了枚举并成功使用了它们......我相信。但是,现在我的输出始终显示名称,但等级始终为 0,无论输入是什么。我可能转换错了吗? atof(s.c_str()) 转换为字符串是正确的吗?
  • 如果没有看到您的新代码,我不确定。也许是时候清理旧调试器并查看s 的值了?您实际上是否将转换后的值存储在总数中?
  • 我有它通过 if (s[0] == '0' || ..........so 测试 s 的第一个字符到 0 到 9 之间上...)
猜你喜欢
  • 1970-01-01
  • 2022-01-05
  • 1970-01-01
  • 1970-01-01
  • 2020-11-24
  • 2021-10-16
  • 1970-01-01
  • 2012-04-11
  • 2013-12-14
相关资源
最近更新 更多