有没有办法在遇到`\ n`时停止std :: cin

时间:2017-02-14 22:55:25

标签: c++ stl getline

除了一件事,我编写的代码运行得很好。我正在制作此代码的任务是将数据输入到程序中作为空格分隔的双精度字符串。并且他们的精确度可能大于10 ^ -25。所以我创建了自己的类来处理它。

问题是,当我编写代码时,我通过手动输入两个值来测试它,每次按Enter键,这样我的程序就可以理解一个双尾的结束而另一个开始(它正在寻找一个基本上'\n'

现在我真的需要调整这段代码,让我使用我的任务输入(空格分隔的双精度列表,如2.521 32.12334656 23.21 .....)。但是我的重载>>中的getline有问题运营商。它只是吃掉'\n'字符并开始寻找更多输入。我可以让它工作的唯一方法是手动输入值并在最后一个值之后手动输入一个额外的空格,然后点击回车。

我在寻求你的帮助。

这是完整的代码:

#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 个答案:

答案 0 :(得分: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 :(得分: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;
}

答案 2 :(得分:-1)

也许你可以使用

std::string temp;
is >> temp;

而不是std::getline()

如果我记得很好,那就打破了空格并将换行符保留在缓冲区中。