我试图编写一个程序,该程序将从用户读取字符串的集合,然后在遇到"."时结束。所以我写了一个do-while循环。

我遇到了这样的事情:循环将始终从其主体内部结束-这正是所希望的结果。

但是,这段代码有些令人讨厌。还有什么更好的方法吗?

要注意的另一件事:我不希望将"."推到向量上,因此这就是为什么我添加了这个小if (temp == ".") break;语句的原因。

#1 楼

不要忘记检查流状态是否有错误或EOF。

while (cin >> temp && temp != ".")
{
    params.push_back(temp);
}



编辑:您不一定需要发明自己的中断条件。已经有一个文件结尾了。您可以阅读字符串,直到达到为止。这样,您的程序也可以很好地处理非交互式输入。要在终端上生成文件结尾,请在Unix / Linux上键入Ctrl + D,在Windows上键入Ctrl + Z。

while (cin >> temp)
{
    params.push_back(temp);
}


评论


\ $ \ begingroup \ $
几乎是一个非常好的解决方案–它只缺少{},即使对于单行主体,我也非常希望看到它。
\ $ \ endgroup \ $
–克里斯托弗·克雷齐格
2011年5月4日在12:18

\ $ \ begingroup \ $
@Christopher:这是个人风格的问题。尽管如此,我将编辑此答案以使其更加清晰。
\ $ \ endgroup \ $
– Andrey Vihrov
2011年5月4日13:17

\ $ \ begingroup \ $
是的,我没有其他意思。 (但请注意,某些版本的gcc会用-Wall标记此类“缺少括号”,这实际上应该是任何开发人员的标准设置之一。)
\ $ \ endgroup \ $
–克里斯托弗·克雷齐格
2011年5月4日14:27

\ $ \ begingroup \ $
几乎是一个非常好的解决方案-它只有那些丑陋,完全不必要的{}污染和混淆了本来不错的代码。 :-)
\ $ \ endgroup \ $
–杰里·科芬(Jerry Coffin)
2011年5月5日,2:40

\ $ \ begingroup \ $
@Christopher哪些版本的GCC对此进行了标记?我一直使用-Wall(及更多),从来没有戴上牙套,也从未见过这个警告。
\ $ \ endgroup \ $
–康拉德·鲁道夫(Konrad Rudolph)
2012年4月21日,下午1:52

#2 楼

我更喜欢:

cin >> temp;
while (temp != ".")
{
   params.push_back(temp);
   cin >> temp;
}


#3 楼

string temp;
vector<string> params;
while (true)
{
    cin >> temp;
    if (temp == ".")
        break;

    params.push_back(temp);

}


该测试-在我的情况下为true,在您的情况下为temp != ".",除非确实如此,否则它永远不会真正运行。因此也可能是true

评论


\ $ \ begingroup \ $
这是我的建议,修改为使用for(;;)而不是{} while(true);我更喜欢Michael K的答案,因为它不会重复循环的“主体”(cin >> temp),而且速度也不慢(尽管仍然需要执行分支)。如果循环的“主体”不止一行,那么显然是代码重复。
\ $ \ endgroup \ $
– mmocny
2011年5月4日,3:14

\ $ \ begingroup \ $
我建议while(true)(不这样做)比for(;;)或while(true)更加清楚意图,即使对于经验不足的程序员也是如此。
\ $ \ endgroup \ $
– Hosam Aly
2011年5月4日,9:36

\ $ \ begingroup \ $
好的,@ Hosam Aly;我已根据您的建议进行了更新。谢谢!
\ $ \ endgroup \ $
–卡尔·曼纳斯特(Carl Manaster)
2011年5月4日13:32

#4 楼

我更喜欢建立一些基础结构,使其余的代码变得微不足道。基础架构可能需要一点额外的工作,但长期节省的费用可能是可观的。在这种情况下,它采用特殊迭代器的形式,该迭代器允许您指定将结束输入的“前哨”。它的作用类似于普通的istream_iterator,只是在构造“范围结束”迭代器时指定了哨兵值。

// sentinel_iterator.h
#pragma once
#if !defined(SENTINEL_ITERATOR_H_)
#define  SENTINEL_ITERATOR_H_
#include <istream>
#include <iterator>

template <class T,
          class charT=char,
          class traits=std::char_traits<charT>,
          class distance = ptrdiff_t>

class sentinel_iterator :
    public std::iterator<std::input_iterator_tag,distance,void,void,void>
{
    std::basic_istream<charT,traits> *is;
    T value;
public:
    typedef charT char_type;
    typedef traits traits_type;
    typedef std::basic_istream<charT,traits> istream_type;

    sentinel_iterator(istream_type& s)
        : is(&s)
    { s >> value; }

    sentinel_iterator(T const &s) : is(0), value(s) { }

    const T &operator*() const { return value;  }
    const T *operator->() const { return &value; }

    sentinel_iterator &operator++() {
        (*is)>>value;
        return *this;
    }

    sentinel_iterator &operator++(int) {
        sentinel_iterator tmp = *this;
        (*is)>>value;
        return (tmp);
    }

    bool operator==(sentinel_iterator<T,charT,traits,distance> const &x) {
        return value == x.value;
    }

    bool operator!=(sentinel_iterator<T,charT,traits,distance> const &x) {
        return !(value == x.value);
    }
};

#endif 


有了它,就可以读取数据变得琐碎:

#include <string>
#include <vector>
#include <algorithm>
#include <iostream>
#include "sentinel_iterator.h"

int main() { 
    // As per spec, read until a "." is entered:
    std::vector<std::string> strings(
        sentinel_iterator<std::string>(std::cin), 
        sentinel_iterator<std::string>("."));

    // It's not restricted to strings either. Read numbers until -1 is entered:
    std::vector<int> numbers(
        sentinel_iterator<int>(std::cin),
        sentinel_iterator<int>(-1));

    // show the strings:
    std::copy(strings.begin(), strings.end(),
        std::ostream_iterator<std::string>(std::cout, "\n"));

    // show the numbers:
    std::copy(numbers.begin(), numbers.end(),
        std::ostream_iterator<int>(std::cout, "\n"));
    return 0;
}


输入以下内容:

This is a string .
1 2 3 5 -1


它产生的输出:

This
is
a
string
1
2
3
5


它基本上适用于定义流提取器并测试相等性的任何类型(即说x==y将编译并产生有意义的结果)。

评论


\ $ \ begingroup \ $
我喜欢这个主意(和+1)。相反,std :: istream_iterator在比较流指针而不是读取值。这具有很小的效率成本,因为构造函数和operator ++都需要一个额外的if()来查看读取是否失败,以便使流指针无效。您的sentinel_iterator不需要它。您还可以使用它从std :: cin读取直到读取失败吗?
\ $ \ endgroup \ $
–TemplateRex
2013年9月17日9:36



#5 楼

如果我们不是在谈论特定于语言的详细信息,那么我会喜欢这样的东西:

// this is inspired by LINQ and C#
var params = Enumerable.Generate<string>(() => {string temp; cin >> temp; return temp; })
                       .TakeWhile(s => s != ".")
                       .ToVector();


其中Enumerable.Generate()是一些lambda,它从cin读取数据。通常回答“如何使用休息时间”的问题。我认为不应使用休息时间,至少在这种琐碎的情况下不应该使用。

评论


\ $ \ begingroup \ $
我不喜欢这种特定语法,但是我喜欢这种方法。
\ $ \ endgroup \ $
– mmocny
2011年5月4日15:07