7

我正在练习用户输入处理。我的目标是让用户输入一行由空格(“”)分隔的整数,将它们作为整数读取,存储它们并稍后处理它们。我偶然发现了一个有趣的问题(至少在我看来),我这样做的方式似乎总是没有读取用户输入的最后一个数字。我将在此处发布整个程序(因为其中包含一些额外的库)。我在程序中留下了一些评论

#include <iostream>
#include <string>
#include <vector>
#include <stdlib.h>

using namespace std;

int main()
{
    //this vector will store the integers
    vector<int> a;
    // this will store the user input
    string inp;
    getline(cin, inp);
    // this string will temporarily store the digits
    string tmp;
    //be sure that the reading part is okay
    cout << inp << endl;
     //until you meet something different than a digit, read char by char and add to string
     for(int i = 0; i < inp.length(); i++)
    {
        if(isdigit(inp[i]))
        {
            tmp +=inp[i];
        }
        else
        {
            // when it is not a character, turn to integer, empty string
            int value = atoi(tmp.c_str());
            a.push_back(value);
            tmp = "";
        }
    }
    // paste the entire vector of integers
    for(int i = 0; i < a.size(); i++)
    {
        cout << a[i] << endl;
    }
    return 0;
}
4

9 回答 9

6

替换此行

for(int i = 0; i <inp.length(); i++)

经过

for(int i = 0; i <= inp.length(); i++)

演示IDEONE

您的代码的问题是:例如25 30 46每当i=7tmp=46您没有inp[8]换行符那样在向量中推动 46,因此您的 for 循环在 i 变为 7 后终止。

请注意i <= inp.length() 在大多数编译器中都能完美运行,因为 \0 被用作/视为哨兵。但是,很少有编译器(如 Microsoft Visual C++)可能显示断言错误:字符串下标超出范围。

于 2013-04-17T13:50:31.910 回答
3

如果该行的最末端是一个数字,那么您不会else在最后一次迭代中点击 ,并且最后一个数字永远不会被推入vector. 最简单的解决方案是在循环之后复制非数字逻辑:

 if (!tmp.empty()) // If tmp has content, we need to put it in the vector.
 {
        int value = atoi(tmp.c_str());
        a.push_back(value);
        tmp = "";
 }

尽管我相信您可以想到一种更好的构建方式。

这是我想出的一个版本std::stringstream,它也避免了atoi

int main()
{
    std::vector<int> ints;
    std::string line;
    std::getline (std::cin, line);
    std::cout << "Read \"" << line << "\"\n";
    std::stringstream ss(line);

    int remaining = line.size();
    while (remaining)
    {
        if(std::isdigit(ss.peek())) // Read straight into an int
        {
            int tmp;
            ss >> tmp;
            ints.push_back(tmp);
        }
        else
        {
            ss.get(); // Eat useless characters
        }

        remaining = line.size()-ss.tellg();
    }

    for (auto i : ints)
        std::cout << i << '\n';

    return 0;
}

跑步:

$ ./a.out <<< "12 34 56"
Read "12 34 56"
12
34
56

请注意,这专门用于处理数字之间的任何旧乱码:

$ ./a.out <<< "12-abc34-56"
Read "12-abc34-56"
12
34
56

如果只有空格,这就更容易了,因为int从 a 读取 sstringstream会自动忽略它。在这种情况下,您只需要:

int tmp;
while (ss >> tmp)
{
    ints.push_back(tmp);
}
于 2013-04-17T13:46:57.927 回答
1

在开始循环之前,在字符串中添加一个空格以确保压入最后一个数字:inp.push_back(' ')

于 2013-04-17T13:49:14.723 回答
1

您的程序需要一个以非数字字符结尾的字符串才能正常工作。试试这个字符串“1 12 14587 15”,因为在您的算法中,当您忘记最后一个空格时,您的程序会将数字存储到 tmp 字符串中,但不将其保存到向量中。要纠正这一点,您需要在第一个循环之后添加最后一个 push_back。

于 2013-04-17T13:47:14.303 回答
1

a仅在找到非数字时才使用新值进行更新。因此,如果您有以数字结尾的字符串,tmp则将包含数字字符串,但您永远不会到达应该执行 push_back 的 else。您可以通过在 for 循环后添加以下代码来解决此问题

if(!tmp.empty()){
    // when it is not a character, turn to integer, empty string
    int value = atoi(tmp.c_str());
    a.push_back(value);
    tmp = "";
}
于 2013-04-17T13:47:20.867 回答
1

您的循环在读取最后一位数字后完成,因此最后一位数字永远不会变成整数。只需在原始 for 循环之后添加一些代码。

for(int i = 0; i < inp.length(); i++)
{
    /* ...... */
}
// add this to read the last digit
if(tmp.length() > 0){
    int value = atoi(tmp.c_str());
    a.push_back(value);
    tmp = "";
}
于 2013-04-17T13:50:24.277 回答
0

当最后一个数字的最后一个数字存储在 tmp 中时,循环结束,因为您已经读取了整个字符串的最后一个字符。当循环结束时 tmp 仍然包含最后一个数字。

1)您可以在循环后将最后一个数字转换并添加到向量。最后一个数字在 tmp 中仍然可用。

2)或者您可以在循环之前在字符串末尾显式添加非数字字符。

于 2013-04-17T13:52:19.713 回答
0

你省略输入。更改您的代码以反映此:

   //this vector will store the integers
    vector<int> a;
    // this will store the user input
    string inp;
    getline(cin, inp);
    // this string will temporarily store the digits
    string tmp;
    //be sure that the reading part is okay
    cout << inp << endl;
     //until you meet something different than a digit, read char by char and add to string
     for(int i = 0; i < inp.length(); i++)
    {
        if(isdigit(inp[i]))
        {
            tmp =inp[i];
            int value = atoi(tmp.c_str());
            a.push_back(value);
        }
        else
        {
            tmp = "";
        }
    }
    // paste the entire vector of integers
    for(int i = 0; i < a.size(); i++)
    {
        cout << a[i] << endl;
    }
    return 0;

或循环替换: for(int i = 0; i <inp.length(); i++)

经过

for(int i = 0; i <= inp.length(); i++)
于 2013-04-17T13:57:04.737 回答
0

你永远不会推回你的最后一个价值。例如,考虑这个输入

40 36

然后,当您阅读时,您会在第一个空格处向后推。但是你永远不会推动 36,因为没有更多的字符。

循环结束后,for()您可以尝试以下操作:

if(!tmp.empty()) {
  a.push_back(tmp);
}
于 2013-04-17T13:48:31.820 回答