Как правильно завершить ввод - PullRequest
0 голосов
/ 19 июня 2020
• 1000 я]. Убедитесь, что у меня есть weight.size () == price.size ()
vector<double> weight;
vector<double> price;

void read_weight() {
  cout << "Input weight" << '\n';

  for (double weights; cin >> weights; ) {
    weight.push_back(weights);

    if (!(cin >> weights)) {
      cin.clear();
      cin.ignore(numeric_limits<double>::max(), '\n' );
      break;
    }
  }
}

void read_price() {
  cout << "Input price" << '\n';

  for (double prices; cin >> prices; ) {
    price.push_back(prices);

    if (!( cin >> prices)) {
      cin.clear();
      cin.ignore( numeric_limits<double>::max(), '\n' );
      break;
    }
  }
}

void calculate() {
  double sum = 0;
  for (int i = 0; i < price.size(); ++i)
    sum += price[i] * weight[i];

  cout << "Sum is " << sum << '\n';
}


int main() {
  read_weight();
  read_price();
  calculate();
}

Это код, который у меня есть, но я не могу понять, как правильно завершить ввод. В предыдущих главах его книги упоминается, что вы можете использовать ввод помимо двойного для завершения (например, |). Однако я узнал, что это только переводит cin в состояние сбоя и не позволяет мне перейти к функции цены. К сожалению, в книге пока не рассказывается, как с этим справиться, поэтому я просто скопировал код cin.clear и cin.ignore в надежде, что это сработает. Но это ничего не дало. Я заметил, что мне действительно разрешили один ввод, если бы я изменил вектор на int вместо double, и меня озадачила разница в поведении. Мне было интересно, может ли кто-нибудь дать мне совет, как это исправить?

Ответы [ 2 ]

2 голосов
/ 19 июня 2020

Вы уже были на полпути. Я написал комментированную замену для read_weights(); вы сможете взять его оттуда.

#include <vector>
#include <limits>
#include <iostream>

// Use return values instead of working on global variables.
// Avoid using global variables whenever possible, they are a 
// maintenance pain.
std::vector< double > read_weights()
{
    std::vector< double > weights;
    double weight;

    // You can embed the \n right in the string, no need to put it as a
    // separate character.
    std::cout << "Input weights; enter a non-number to terminate input.\n";

    // If anything not double is entered, cin goes into fail state --
    // that is our terminating condition right there, so use it!
    while ( std::cin >> weight )
    {
        weights.push_back( weight );
    }

    // Clean up cin
    std::cin.clear();
    // Use the correct type for max(); you had 'double' here...
    cin.ignore( numeric_limits< std::streamsize >::max(), '\n' );

    // Don't worry about the apparent copying of the vector upon return.
    // Any modern compiler should be able to optimize this away.
    return weigths;
}

Простой main () для тестирования:

int main()
{
    std::vector< double > weights = read_weights();

    std::cout << "Vector contents:\n";

    for ( auto & v : weights )
    {
        std::cout << v << "\n";
    }
}

Теперь все, что вам нужно добавить, это read_price() ... теперь подожди, не так ли? Потому что все, что вы на самом деле делаете, это то же самое, что и в read_weights(), вводя двойные числа! Так что переместите приглашение ввода из read_weights() и сделайте его одной функцией, read_values(), которую вы вызываете дважды, один раз для получения weights и один раз для получения prices ...

int main()
{
    std::cout << "Enter weights; enter a non-number to terminate input.\n";
    std::vector< double > weights = read_values();
    std::cout << "Enter prices; enter a non-number to terminate input.\n";
    std::vector< double > prices = read_values();
    // ...
}

Для функции calculate используйте ссылки на параметры, чтобы векторы не нужно было копировать:

void calculate( std::vector<double> & weights, std::vector<double> & prices )

И как только вы все это запустите, имейте в виду что позже вы (или, по крайней мере, должен ) будете изучать <algorithm>, функторы и лямбды ... которые должны устранить необходимость в calculate и заменить его элегантным - лайнер ... но это еще не все, и сейчас я не хочу вас этим путать.

2 голосов
/ 19 июня 2020

Вы можете использовать std :: getline, чтобы прочитать всю строку из cin в строку. После этого нужно определить, является ли введенная строка двойной или нет. Обычно я бы не рекомендовал зацикливаться на регулярных выражениях (я не часто их использую в C ++), но в данном случае я считаю, что это довольно простое и надежное решение. Если строка имеет формат «32.23» (цифры, точки, цифры), вы конвертируете ее в двойную, используя std :: stod, pu sh, что в вектор, и продолжаете читать из cin. Если это не так, вы нарушите l oop и go в потоке программы.

Не используйте глобальные переменные, используйте локальные и передавайте их по порядку.

Также обратите внимание, что ваши функции read_price и read_weight почти идентичны. В таком случае вы определенно захотите написать только одну (параметризованную) функцию. В этом случае вам даже не нужны параметры, вы можете просто использовать одну и ту же функцию для обоих.

(Вы также можете напрямую считывать свои значения в двойные переменные из потока (std :: cin), который может считаться более элегантным, поскольку вам нужно меньше преобразований, однако приведенный ниже метод прост, и вам не нужно беспокоиться о том, что вводится в std :: cin)

#include <vector>
#include <string>
#include <iostream>
#include <regex>


std::vector<double> get_doubles_from_cin(){
    std::vector<double> doubles;
    std::regex double_regex ("\\d+\\.\\d+");
    std::string input;
    while(std::getline(std::cin, input)){
       if (std::regex_match(input, double_regex)){
           doubles.push_back(std::stod(input));
       }
       else{
           break;
       }
   }
    return doubles;
}


void calculate(std::vector<double>& weights, std::vector<double>& prices) {
  double sum = 0;
  for (int i = 0; i < prices.size(); ++i) {
      sum += weights[i] * prices[i];
  }
  std::cout << "Sum is " << sum << '\n';
}


int main() {
    std::cout << "Enter weights" << std::endl;
    auto weights = get_doubles_from_cin();
    std::cout << "Enter prices" << std::endl;
    auto prices = get_doubles_from_cin();
    calculate(weights, prices);
}
...