Прочитать список двойников, разделенных пробелами (или другим разделителем), многократно и для разных целей - PullRequest
1 голос
/ 22 марта 2011

Я очень новичок в 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, но мне не удалось вылечить его.

Вопрос: Как мне это запрограммировать? Какой наименее болезненный способ преодолеть проблему? Заранее спасибо!

Ответы [ 4 ]

2 голосов
/ 22 марта 2011

Проблема: Когда я пытаюсь остановить первый цикл и перейти ко второму, нажав 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>();
}
0 голосов
/ 22 марта 2011

Вам действительно нужно переосмыслить свой интерфейс.

Как насчет

SUM 1.9 1.3
AVERAGE 1 4 6
DONE

Используйте cout >> aString, чтобы получить ключевое слово, затем получите числа так же, как сейчас.

0 голосов
/ 22 марта 2011

Если 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, который показывает фактический цикл для удобства использования.

0 голосов
/ 22 марта 2011

Используйте 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";
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...