2017-02-14 12 views
0

Я написал код, который работает очень хорошо, за исключением одного. Задача, которую я делаю для этого кода для ввода данных в программу как пробельная разделенная строка удвоений. И их точность может быть больше 10^-25. Поэтому я создал свой собственный класс, который может справиться с этим.Есть ли способ остановить std :: cin, когда он встречает ` n`

Проблема в том, что когда я писал код, я тестировал его, введя два значения в консоль вручную каждый раз, нажимая enter, чтобы моя программа могла понять, где заканчивается один двойной, и другой запускается (он искал a '\n' в основном).

Теперь мне действительно нужно адаптировать этот код, чтобы я работал с вводом моей задачи (пробельный отдельный список удвоений вроде 2.521 32.12334656 23.21 .....). Но у меня проблема с getline в моем перегруженном >> операторе. Он просто ест символ '\n' и начинает искать больше ввода. Единственный способ, которым я могу заставить его работать, - вручную ввести значения и вручную ввести дополнительные пробелы после последнего значения и только затем нажать enter.

Я прошу вас о помощи.

Вот полный код:

#include <iostream> 
#include <string> 
#include <algorithm> 


class BigNumber { 
private: 
    std::string fullPart; 
    std::string floatPart; 

public: 
    BigNumber() : fullPart("0"), floatPart("0") {} 


    friend std::ostream & operator << (std::ostream & os, const BigNumber & bn); 
    friend std::istream & operator >> (std::istream & os, BigNumber & bn); 

    void operator+=(BigNumber & bn); 
}; 

int main() 
{ 
    BigNumber bn, bntemp; 

    while (std::cin >> bntemp) 
    { 
     bn += bntemp; 

     if (std::cin.peek() == '\n') 
      break; 
    } 

    std::cout << bn << std::endl; 
    return 0; 
} 

void addFullPart(const std::string & add, std::string & add_to) 
{ 
    auto addConv = std::stold(add); 
    auto addToConv = std::stold(add_to); 

    auto newFull = std::to_string(addConv + addToConv); 
    add_to = std::string(newFull.begin(), std::find(newFull.begin(), newFull.end(), '.')); 
} 

bool carryReminder(std::string & add_to, int32_t indx_from) 
{ 
    for (auto curr = indx_from; curr >= 0; --curr) 
    { 
     if (add_to[curr] != '9') 
     { 
      ++(add_to[curr]); 
      return true; 
     } 
     else 
      add_to[curr] = '0'; 
    } 

    return false; 
} 

std::pair<std::string, int32_t> addFloatPart(std::string & add, std::string & add_to) 
{ 
    std::string resultFloat; 

    int32_t reminderReturn{}; 

    // don't forget to reverse str 
    if (add.size() != add_to.size()) 
    { 
     // add remaining 0's 
     if (add.size() < add_to.size()) 
     { 
      while (add.size() != add_to.size()) 
      { 
       auto tempBigger = add_to.back(); 
       add_to.pop_back(); 
       resultFloat.push_back(tempBigger); 
      } 
     } 
     else 
     { 
      while (add.size() != add_to.size()) 
      { 
       auto tempBigger = add.back(); 
       add.pop_back(); 
       resultFloat.push_back(tempBigger); 
      } 
     } 
    } 

    // now they are equal and have a form of 120(3921) 595 

    for (int32_t i = add_to.size() - 1; i >= 0; --i) 
    { 
     int32_t add_toDigit = add_to[i] - '0'; 
     int32_t addDigit = add[i] - '0'; 

     if (add_toDigit + addDigit >= 10) 
     { 
      resultFloat.append(std::to_string((add_toDigit + addDigit) - 10)); 
      // we have a remainder 
      if (i == 0 || !carryReminder(add_to, i - 1)) 
       reminderReturn = 1; 
     } 
     else 
     { 
      resultFloat.append(std::to_string(add_toDigit + addDigit)); 
     } 
    } 

    std::reverse(resultFloat.begin(), resultFloat.end()); 

    return std::make_pair(resultFloat, reminderReturn); 

} 


std::ostream & operator<<(std::ostream & os, const BigNumber & bn) 
{ 
    os << bn.fullPart << "." << bn.floatPart; 
    return os; 
} 

std::istream & operator>>(std::istream & is, BigNumber & bn) 
{ 
    std::string temp; 
    std::getline(is, temp, ' '); 

    auto fullPartTemp = std::string(temp.begin(), std::find(temp.begin(), temp.end(), '.')); 
    auto floatPartTemp = std::string(std::find(temp.begin(), temp.end(), '.') + 1, temp.end()); 

    bn.floatPart = floatPartTemp; 
    bn.fullPart = fullPartTemp; 

    return is; 
} 

void BigNumber::operator+=(BigNumber & bn) 
{ 
    auto pair = addFloatPart(bn.floatPart, floatPart); 

    floatPart = pair.first; 

    if (pair.second > 0) 
     addFullPart(std::to_string(std::stoi(bn.fullPart) + 1), fullPart); 
    else 
     addFullPart(bn.fullPart, fullPart); 
} 

ответ

3

Я предлагаю вам сначала использовать getline для чтения строки. Затем вы можете сделать istringstream и использовать >>. В частности, можно добавить #include <sstream> и изменить функцию main на следующее:

int main() 
{ 
    BigNumber bn, bntemp; 

    std::string temp; 
    std::getline(std::cin, temp); 
    std::istringstream ln(temp); 
    while (ln.good()) { 
     ln >> bntemp; 
     bn += bntemp; 
    } 

    std::cout << bn << std::endl; 
    return 0; 
} 
+1

Это, как я хотел бы предложить сделать это. Однако вы должны заменить 'while (ln.good()) {ln >> bntemp; bn + = bntemp; } 'с' while (ln >> bntemp) {bn + = bntemp; } 'вместо –

-1

Может быть, вы могли бы использовать

std::string temp; 
is >> temp; 

вместо std::getline().

Если я хорошо помню, что ломается на пробелы и сохраняет новую строку в буфере.

1

Необходимо внести два изменения. В main

Отказано в подсмотре. Слишком хрупкий.

int main() 
{ 
    BigNumber bn, bntemp; 
    std::string line; 
    std::getline(std::cin, line); 
    std::stringstream stream(line); 
    while (stream >> bntemp) 
    { 
     bn += bntemp; 
    } 

    std::cout << bn << std::endl; 
    return 0; 
} 

И operator>>

std::istream & operator >> (std::istream & is, BigNumber & bn) 
{ 
    std::string temp; 
    // also do NOTHING if the read fails! 
    if (std::getline(is, temp, ' ')) 
    { 
     // recommend some isdigit testing in here to make sure you're not 
     // being fed garbage. Set fail flag in stream and bail out. 
     auto floatPartTemp = std::string(temp.begin(), std::find(temp.begin(), temp.end(), '.')); 

     // if there is no . you are in for a world of hurt here 
     auto floatPartTemp = std::string(std::find(temp.begin(), temp.end(), '.') + 1, temp.end()); 

     bn.floatPart = ; 
     bn.fullPart = fullPartTemp; 
    } 
    return is; 
} 

Так это должно выглядеть примерно

std::istream & operator >> (std::istream & is, BigNumber & bn) 
{ 
    std::string temp; 
    if (std::getline(is, temp, ' ')) 
    { 
     if (std::all_of(temp.cbegin(), temp.cend(), [](char ch) { return isdigit(ch) || ch == '.'; })) 
     { 
      auto dotpos = std::find(temp.begin(), temp.end(), '.'); 
      bn.fullPart = std::string(temp.begin(), dotpos); 
      std::string floatPartTemp; 
      if (dotpos != temp.end()) 
      { 
       floatPartTemp = std::string(dotpos + 1, temp.end()); 
      } 
      bn.floatPart = floatPartTemp; 
     } 
     else 
     { 
      is.setstate(std::ios::failbit); 
     } 
    } 
    return is; 
}