出于不同目的重复读取由空格(或其他分隔符)分隔的双精度列表

发布于 2024-10-25 09:14:09 字数 1278 浏览 4 评论 0原文

我对 C++ 非常陌生,遇到了以下问题。

我的目标: 我想要一个执行以下操作的代码:

  1. 用户输入包含以某种方式分隔的双精度数的行
  2. 双精度数被解析为双精度数数组
  3. 对数组进行计算(*)。例如,它的总和
  4. 如果用户不停止循环,它会读取一个新行,然后循环回到 1。
  5. 一旦用户中断第一个循环(通过输入空行或类似的内容),就会开始一个新循环。
  6. 用户输入包含以某种方式分隔的双精度数的行
  7. 双精度数将被解析为双精度数数组
  8. 对数组进行计算(**)。例如它的平均值。
  9. 用户制动第二个循环。
  10. 程序退出。

我的代码:

#include <iostream>

int main()
{
    do {
        double x1, x2, x3, y1, y2, y3;
        std::cin >> x1 >> y1 >> x2 >> y2 >> x3 >> y3;
        if (!std::cin){   
            break;
        }
        std::cout << "\n The sum is: " << (x1+y1+x2+y2+x3+y3) << "\n";
    } while (1);

    do {
        double x1, x2, x3, y1, y2, y3;
        std::cin >> x1 >> y1 >> x2 >> y2 >> x3 >> y3;
        if (!std::cin){   
            break;
        }
        std::cout << "\n The average is: " << (x1+y1+x2+y2+x3+y3)/6 << "\n";
    } while (1);
    return 0;
}

问题: 当我尝试停止第一个循环,并通过按 CTRL-D 或给出一个字母作为输入移动到第二个循环时,程序将退出并跳过第二个循环。我意识到这与cin机制有关,但我未能治愈它。

问题:我应该如何编程?解决这个问题最痛苦的方法是什么?提前致谢!

I am very much new into C++ and I ran into the following problem.

My goal:
I want to have a code which does the following:

  1. The user enters a line containing doubles separated somehow
  2. The doubles are being parsed into an array of doubles
  3. A computation(*) on the array takes place. For example its sum
  4. If the user doesn't brake the loop, it reads a new line, and loop back to 1.
  5. Once the user broke the first loop (by entering empty line or something like that), a new one starts.
  6. The user enters a line containing doubles separated somehow
  7. The doubles are being parsed into an array of doubles
  8. A computation(**) on the array takes place. For example its average.
  9. User brakes the second loop.
  10. Program quits.

My code:

#include <iostream>

int main()
{
    do {
        double x1, x2, x3, y1, y2, y3;
        std::cin >> x1 >> y1 >> x2 >> y2 >> x3 >> y3;
        if (!std::cin){   
            break;
        }
        std::cout << "\n The sum is: " << (x1+y1+x2+y2+x3+y3) << "\n";
    } while (1);

    do {
        double x1, x2, x3, y1, y2, y3;
        std::cin >> x1 >> y1 >> x2 >> y2 >> x3 >> y3;
        if (!std::cin){   
            break;
        }
        std::cout << "\n The average is: " << (x1+y1+x2+y2+x3+y3)/6 << "\n";
    } while (1);
    return 0;
}

The Problem:
When I try to stop the first loop, and move to the second by either hitting CTRL-D or giving a letter as input, then the program quits and skips the second loop. I realized that it relates to the cin mechanism, but I failed to cure it.

The question: How should I program this? What is the least painful manner to overcome the problem? Thanks in advance!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

还在原地等你 2024-11-01 09:14:09

问题:当我尝试停止第一个循环,并通过按 CTRL-D 或给出一个字母作为输入移动到第二个循环时,程序将退出并跳过第二个循环。我意识到这与cin机制有关,但我未能治愈它。

这是因为当您尝试读取字母或 EOF (Ctrl-D) 时,这会将流的状态设置为错误状态。一旦发生这种情况,流上的所有操作都会失败(直到您重置它)。这可以通过调用clear()来完成

std::cin.clear();

问题:我应该如何编程?解决这个问题最痛苦的方法是什么?

我不会使用这种技术。
我会使用类似空行的东西作为循环之间的分隔符。因此,代码如下所示:

while(std::getline(std::cin, line) && !line.empty())
{
      // STUFF
}
while(std::getline(std::cin, line) && !line.empty())
{
      // STUFF
}

试试这个:
注意:在 C++ 中,当数字以空格分隔时,流效果最佳。因此,只需使用空格或制表符来分隔数字即可。

#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <iterator>
#include <algorithm>

struct Average
{
    Average(): result(0.0), count(0)            {}
    void operator()(double const& val)          { result  += val;++count;}
    operator double()                           { return (count == 0) ? 0.0 : result/count;}
    double  result;
    int     count;
};
struct Sum
{
    Sum(): result(0.0)                          {}
    void operator()(double const& val)          { result  += val;}
    operator double()                           { return result;}
    double result;
};

int main()
{
    std::string line;

    // Read a line at a time.
    // If the read fails or the line read is empty then stop looping.
    while(std::getline(std::cin, line) && !line.empty())
    {
        // In C++ we use std::Vector to represent arrays.
        std::vector<double>     data;
        std::stringstream       lineStream(line);

        // Copy a set of space separated integers from the line into data.
        // I know you wanted doubles (I do this next time)
        // I just wanted to show how easy it is to change between the types being
        // read. So here I use integers and below I use doubles.
        std::copy(  std::istream_iterator<int>(lineStream),
                    std::istream_iterator<int>(),
                    std::back_inserter(data));

        // Sum is a functor type.
        // This means when you treat it like a function then it calls the method operator()
        // We call sum(x) for each member of the vector data
        Sum sum;
        sum = std::for_each(data.begin(), data.end(), sum);
        std::cout << "Sum: " << static_cast<double>(sum) << "\n";
    }

    // Read a line at a time.
    // If the read fails or the line read is empty then stop looping.
    while(std::getline(std::cin, line) && !line.empty())
    {
        // In C++ we use std::Vector to represent arrays.
        std::vector<double>     data;
        std::stringstream       lineStream(line);

        // Same as above but we read doubles from the input not integers.
        // Notice the sleigh difference from above.
        std::copy(  std::istream_iterator<double>(lineStream),
                    std::istream_iterator<double>(),
                    std::back_inserter(data));

        // Average is a functor type.
        // This means when you treat it like a function then it calls the method operator()
        // We call average(x) for each member of the vector data
        Average average;
        average = std::for_each(data.begin(), data.end(), average);
        std::cout << "Average: " << static_cast<double>(average) << "\n";
    }
}

// 或者我们可以稍微模板化代码:

template<typename T, typename F>
void doAction()
{
    std::string line;

    // Read a line at a time.
    // If the read fails or the line read is empty then stop looping.
    while(std::getline(std::cin, line) && !line.empty())
    {
        std::stringstream       lineStream(line);

        // F is a functor type.
        // This means when you treat it like a function then it calls the method operator()
        // We call action(x) for each object type 'T' that we find on the line.
        // Notice how we do not actual need to store the data in an array first
        // We can actually processes the data as we read it from the line
        F action;
        action = std::for_each(  std::istream_iterator<T>(lineStream),
                                 std::istream_iterator<T>(),
                                 action);
        std::cout << "Action Result: " << static_cast<double>(action) << "\n";
    }
}

int main()
{
    doAction<int, Sum>();
    doAction<double, Average>();
}

The Problem: When I try to stop the first loop, and move to the second by either hitting CTRL-D or giving a letter as input, then the program quits and skips the second loop. I realized that it relates to the cin mechanism, but I failed to cure it.

This is because when you try and read a letter or EOF (Ctrl-D) this sets the state of the stream into a bad state. Once this happens all operations on the stream fail (until you reset it). This can be done by calling clear()

std::cin.clear();

The question: How should I program this? What is the least painful manner to overcome the problem?

I would not use this technique.
I would use something like an empty line as a separator between loop. Thus the code looks like this:

while(std::getline(std::cin, line) && !line.empty())
{
      // STUFF
}
while(std::getline(std::cin, line) && !line.empty())
{
      // STUFF
}

Try this:
Note: in C++ streams work best when numbers are space separated. So it is easy just use space or tab to separate the numbers.

#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <iterator>
#include <algorithm>

struct Average
{
    Average(): result(0.0), count(0)            {}
    void operator()(double const& val)          { result  += val;++count;}
    operator double()                           { return (count == 0) ? 0.0 : result/count;}
    double  result;
    int     count;
};
struct Sum
{
    Sum(): result(0.0)                          {}
    void operator()(double const& val)          { result  += val;}
    operator double()                           { return result;}
    double result;
};

int main()
{
    std::string line;

    // Read a line at a time.
    // If the read fails or the line read is empty then stop looping.
    while(std::getline(std::cin, line) && !line.empty())
    {
        // In C++ we use std::Vector to represent arrays.
        std::vector<double>     data;
        std::stringstream       lineStream(line);

        // Copy a set of space separated integers from the line into data.
        // I know you wanted doubles (I do this next time)
        // I just wanted to show how easy it is to change between the types being
        // read. So here I use integers and below I use doubles.
        std::copy(  std::istream_iterator<int>(lineStream),
                    std::istream_iterator<int>(),
                    std::back_inserter(data));

        // Sum is a functor type.
        // This means when you treat it like a function then it calls the method operator()
        // We call sum(x) for each member of the vector data
        Sum sum;
        sum = std::for_each(data.begin(), data.end(), sum);
        std::cout << "Sum: " << static_cast<double>(sum) << "\n";
    }

    // Read a line at a time.
    // If the read fails or the line read is empty then stop looping.
    while(std::getline(std::cin, line) && !line.empty())
    {
        // In C++ we use std::Vector to represent arrays.
        std::vector<double>     data;
        std::stringstream       lineStream(line);

        // Same as above but we read doubles from the input not integers.
        // Notice the sleigh difference from above.
        std::copy(  std::istream_iterator<double>(lineStream),
                    std::istream_iterator<double>(),
                    std::back_inserter(data));

        // Average is a functor type.
        // This means when you treat it like a function then it calls the method operator()
        // We call average(x) for each member of the vector data
        Average average;
        average = std::for_each(data.begin(), data.end(), average);
        std::cout << "Average: " << static_cast<double>(average) << "\n";
    }
}

// Or we could templatize the code slightly:

template<typename T, typename F>
void doAction()
{
    std::string line;

    // Read a line at a time.
    // If the read fails or the line read is empty then stop looping.
    while(std::getline(std::cin, line) && !line.empty())
    {
        std::stringstream       lineStream(line);

        // F is a functor type.
        // This means when you treat it like a function then it calls the method operator()
        // We call action(x) for each object type 'T' that we find on the line.
        // Notice how we do not actual need to store the data in an array first
        // We can actually processes the data as we read it from the line
        F action;
        action = std::for_each(  std::istream_iterator<T>(lineStream),
                                 std::istream_iterator<T>(),
                                 action);
        std::cout << "Action Result: " << static_cast<double>(action) << "\n";
    }
}

int main()
{
    doAction<int, Sum>();
    doAction<double, Average>();
}
站稳脚跟 2024-11-01 09:14:09

使用 std::cin.get()。它将在第一个输入的字符后返回。在这种情况下,您不需要循环,而是需要一些东西。像这样:

double x1, x2, x3, y1, y2, y3;
std::cin >> x1 >> y1 >> x2 >> y2 >> x3 >> y3;
std::cin.get();
std::cout << "\n The sum is: " << (x1+y1+x2+y2+x3+y3) << "\n";

double x1, x2, x3, y1, y2, y3;
std::cin >> x1 >> y1 >> x2 >> y2 >> x3 >> y3;
std::cin.get();
std::cout << "\n The average is: " << (x1+y1+x2+y2+x3+y3)/6 << "\n";

Use std::cin.get(). It will return after the first entered character. You won't need loops in this case, but rather get smth. like this:

double x1, x2, x3, y1, y2, y3;
std::cin >> x1 >> y1 >> x2 >> y2 >> x3 >> y3;
std::cin.get();
std::cout << "\n The sum is: " << (x1+y1+x2+y2+x3+y3) << "\n";

double x1, x2, x3, y1, y2, y3;
std::cin >> x1 >> y1 >> x2 >> y2 >> x3 >> y3;
std::cin.get();
std::cout << "\n The average is: " << (x1+y1+x2+y2+x3+y3)/6 << "\n";
无名指的心愿 2024-11-01 09:14:09

如果 std::cin 收到错误类型的输入,它将进入失败状态 - 您可以使用 (!std::cin) 进行测试。但输入数据也保留在流中。

因此,除了检查失败状态之外,您还必须清除失败状态(std::cin.clear();)并从输入流中删除未读数据(std:: cin.ignore();):

  #include <iostream>

  int main()
  {
     do {
        std::cout << "\nInsert 6 Numbers for sum or anything else to break:\n";
        double x1, x2, x3, y1, y2, y3;
        std::cin >> x1 >> y1 >> x2 >> y2 >> x3 >> y3;
        if (!std::cin){
           std::cin.clear();
           std::cin.ignore();
           break;
        }
        std::cout << "\n The sum is: " << (x1+y1+x2+y2+x3+y3) << "\n";
     } while (1);

     do {
        std::cout << "\nInsert 6 Numbers for average or anything else to break:\n";
        double x1, x2, x3, y1, y2, y3;
        std::cin >> x1 >> y1 >> x2 >> y2 >> x3 >> y3;
        if (!std::cin){   
           std::cin.clear();
           std::cin.ignore();
           break;
        }
        std::cout << "\n The average is: " << (x1+y1+x2+y2+x3+y3)/6 << "\n";
     } while (1);

     return 0;
  }

我还添加了一个 cout,它显示了实际循环的可用性。

If std::cin gets input of wrong type it goes into fail-state - which you test with (!std::cin). But also the input-data is left on the stream.

So additionally to check the fail-state you have to clear the fail-state (std::cin.clear();)and remove the unread data from input-stream (std::cin.ignore();):

  #include <iostream>

  int main()
  {
     do {
        std::cout << "\nInsert 6 Numbers for sum or anything else to break:\n";
        double x1, x2, x3, y1, y2, y3;
        std::cin >> x1 >> y1 >> x2 >> y2 >> x3 >> y3;
        if (!std::cin){
           std::cin.clear();
           std::cin.ignore();
           break;
        }
        std::cout << "\n The sum is: " << (x1+y1+x2+y2+x3+y3) << "\n";
     } while (1);

     do {
        std::cout << "\nInsert 6 Numbers for average or anything else to break:\n";
        double x1, x2, x3, y1, y2, y3;
        std::cin >> x1 >> y1 >> x2 >> y2 >> x3 >> y3;
        if (!std::cin){   
           std::cin.clear();
           std::cin.ignore();
           break;
        }
        std::cout << "\n The average is: " << (x1+y1+x2+y2+x3+y3)/6 << "\n";
     } while (1);

     return 0;
  }

I also added an cout which shows the actual loop for usability.

初懵 2024-11-01 09:14:09

您确实需要重新考虑您的用户界面。

怎么样

SUM 1.9 1.3
AVERAGE 1 4 6
DONE

使用cout>> aString 来获取关键字,然后像现在一样获取数字。

You really need to rethink you UI.

How about

SUM 1.9 1.3
AVERAGE 1 4 6
DONE

Use cout >> aString to get the keyword, then get the numbers the same way you do now.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文