【问题标题】:why does this routine return an array of length 0?为什么这个例程返回一个长度为 0 的数组?
【发布时间】:2020-12-22 07:52:32
【问题描述】:

大家,这是我编写的一个函数,用于读取用户输入,它是一个未知大小的双精度向量,输入必须在按下“输入”时终止:

vector<double> read_array()
{
    vector<double> array_in;

    double el;

    while (!cin.get())
    {
        cin >> el;
        array_in.push_back(el);
    }

    return array_in;
}

为了说明它考虑以下代码:

void init() // the function that calls the read_array function
{
    cout << "Enter array X: " << endl;
    
    vector<double> X = read_array();
    
    int l = X.size();

    cout << l << endl;
}

提示时的典型输入是: 1(空格)2(空格)3(空格)4(输入)

当按下回车键时,输入终止,变量 'l' 被初始化但等于 0 但是,当按下回车键时,数组大小为 0。调试它使它看起来好像从来没有像那样进入循环。

如果输入值不是数组,同样的例程也能正常工作。

提前感谢大家!

【问题讨论】:

  • 我建议使用GNU readline 从您的用户那里获取您的线路,然后对其进行解析(可能使用std::istringstream
  • 您给出的确切实际输入是什么?您使用的 get 重载并不像您想象的那样有效。
  • @Someprogrammerdude,当我点击(输入)输入停止时,我输入“1(空格)2(空格)3(输入)”,该例程适用于非数组类型的数据
  • 很难猜出你认为!cin.get() 做了什么,但它绝对不会那样做。
  • 实际上,到目前为止,没有人评论 !std:cin.get() 实际上 做了什么(我忘了在我原来的答案中提到它;现在已修复):std::cin.get() 刚刚得到下一个字符。如果该字符不是 '\0' 否定,它将是 false 并且不会进入循环。似乎希望它做类似'\n' != std::cin.peek() 的事情,但即使这样也不够,因为可能还有其他空白字符。

标签: c++ iostream


【解决方案1】:

我不知道您希望std::cin.get() 做什么,但根据您的评论,您似乎希望它以某种方式处理行尾:它没有。它只是读取下一个不太可能对您有多大好处的字符。特别是,如果字符不是'\0',则否定它将导致布尔值false。也就是说,循环原则上应该工作除非您只输入一个数字数值,后跟(可能在空格之后)一个非数字或输入的结尾。

处理基于行的输入的最简单方法是使用std::getline() 将行读入std::string,然后使用std::istringstream 解析该行:

std::vector<double> read_array() {
    std::vector<double> result;
    if (std::string line; std::getline(std::cin, line)) {
        std::istringstream lin(line);
        for (double tmp; std::cin >> tmp; ) {
            result.push_back(tmp);
        }
    }
    return result;
}

由于std::cin只在读行时涉及,std::cin.fail()在解析doubles失败时不会被设置。也就是说,你可以读取多行包含doubles 的数组,每一行也可以为空。

如果您不想阅读辅助行,则需要更多地了解 C++ 中格式化输入的工作原理:它从跳过空格开始。由于换行符是空格,因此您需要自己阅读空格并在它碰巧是换行符或非空格时停止。我会使用一个函数来跳过它返回false,如果它到达一个换行符(它仍然被提取):

bool skip_non_nl_ws(std::istream& in) {
    for (int c; std::isspace(c = in.peek()); std::cin.ignore()) {
        if (c == '\n') {
            return false;
        }
    }
    return true;
}

std::vector<double> read_array() {
    std::vector<double> result;
    for (double tmp; skip_non_nl_ws(std::cin) && std::cin >> result); ) {
        result.push_back(tmp);
    }
    return result;
}

这种方法有一个类似的属性,std::ios_base::failbit 不会被设置。但是,如果一行中的任何字符都无法解析为double,则该位将被设置。这样您就可以检测输入错误。使用std::getline() 的方法将继续下一行。

【讨论】:

  • 请解释一下if (std::string line; std::getline(std::cin, line))这一行
  • 这是一个if-statement,声明了一个局部变量(line),它用于表达式std::getline(std::cin, line)读取一行。如果std::getline() 失败(即它无法从std::cin 中提取任何字符),则从std::getline() 返回的流将转换为false,否则转换为true。然后std::getline() 的结果只在成功的情况下使用。
猜你喜欢
  • 1970-01-01
  • 2012-05-23
  • 1970-01-01
  • 2020-08-07
  • 2017-05-01
  • 1970-01-01
  • 2023-03-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多