如何打印出矢量的内容?

for*_*win 251 c++ cout vector stdvector output

我想用C++打印出一个向量的内容,这就是我所拥有的:

#include <iostream>
#include <fstream>
#include <string>
#include <cmath>
#include <vector>
#include <sstream>
#include <cstdio>
using namespace std;

int main()
{
    ifstream file("maze.txt");
    if (file) {
        vector<char> vec(istreambuf_iterator<char>(file), (istreambuf_iterator<char>()));
        vector<char> path;
        int x = 17;
        char entrance = vec.at(16);
        char firstsquare = vec.at(x);
        if (entrance == 'S') { 
            path.push_back(entrance); 
        }
        for (x = 17; isalpha(firstsquare); x++) {
            path.push_back(firstsquare);
        }
        for (int i = 0; i < path.size(); i++) {
            cout << path[i] << " ";
        }
        cout << endl;
        return 0;
    }
}
Run Code Online (Sandbox Code Playgroud)

如何将矢量内容打印到屏幕上?

Zor*_*war 357

纯粹回答你的问题,你可以使用迭代器:

std::vector<char> path;
// ...
for (std::vector<char>::const_iterator i = path.begin(); i != path.end(); ++i)
    std::cout << *i << ' ';
Run Code Online (Sandbox Code Playgroud)

如果要在for循环中修改向量的内容,则使用iterator而不是const_iterator.

但是关于这一点可以说更多.如果您只想要一个可以使用的答案,那么您可以在这里停下来; 否则,请继续阅读.

auto(C++ 11)/ typedef

这不是另一种解决方案,而是对上述iterator解决方案的补充.如果您使用的是C++ 11标准(或更高版本),则可以使用该auto关键字来帮助提高可读性:

for (auto i = path.begin(); i != path.end(); ++i)
    std::cout << *i << ' ';
Run Code Online (Sandbox Code Playgroud)

但是类型i将是非const(即编译器将使用std::vector<char>::iterator的类型i).

在这种情况下,你也可以只使用一个typedef(不限于C++ 11,并且无论如何都非常有用):

typedef std::vector<char> Path;
Path path;
// ...
for (Path::const_iterator i = path.begin(); i != path.end(); ++i)
    std::cout << *i << ' ';
Run Code Online (Sandbox Code Playgroud)

计数器

当然,您可以使用整数类型来记录您在for循环中的位置:

for(int i=0; i<path.size(); ++i)
  std::cout << path[i] << ' ';
Run Code Online (Sandbox Code Playgroud)

如果要执行此操作,最好使用容器的成员类型(如果它们可用且适当).std::vector具有size_type为此作业调用的成员类型:它是size方法返回的类型.

// Path typedef'd to std::vector<char>
for( Path::size_type i=0; i<path.size(); ++i)
  std::cout << path[i] << ' ';
Run Code Online (Sandbox Code Playgroud)

为什么不在iterator解决方案上使用它呢?对于简单的情况,您也可以这样做,但重点是iterator该类是一个对象,旨在为更复杂的对象执行此工作,而这个解决方案并不理想.

基于范围的循环(C++ 11)

请参阅Jefffrey的解决方案.在C++ 11(及更高版本)中,您可以使用新的基于范围的for循环,如下所示:

for (auto i: path)
  std::cout << i << ' ';
Run Code Online (Sandbox Code Playgroud)

由于path是项目的向量(显式std::vector<char>),因此对象i是向量项的类型(即,显式地,它是类型char).该对象i具有一个值,该值是path对象中实际项的副本.因此,i循环中的所有更改path本身都不会保留.此外,如果您想强制执行,你不希望能够改变的复制价值的事实,i在循环中,你可以强制的类型iconst char这样的:

for (const auto i: path)
  std::cout << i << ' ';
Run Code Online (Sandbox Code Playgroud)

如果您想修改项目path,可以使用参考:

for (auto& i: path)
  std::cout << i << ' ';
Run Code Online (Sandbox Code Playgroud)

即使您不想修改path,如果复制对象很昂贵,您应该使用const引用而不是按值复制:

for (const auto& i: path)
  std::cout << i << ' ';
Run Code Online (Sandbox Code Playgroud)

性病::复制

约书亚的回答.您可以使用STL算法std::copy将矢量内容复制到输出流.如果您对它感到满意,这是一个优雅的解决方案(此外,它非常有用,不仅仅是在打印矢量内容的情况下).

的std :: for_each的

请参阅Max的解决方案.std::for_each对于这个简单的场景,使用是过度的,但如果你想做的不仅仅是打印到屏幕,它是一个非常有用的解决方案:使用std::for_each允许你对矢量内容做任何(明智的)操作.

overload ostream :: operator <<

请参阅Chris的回答,这是对其他答案的补充,因为您仍需要在重载中实现上述解决方案之一.在他的例子中,他在for循环中使用了一个计数器.例如,这就是你如何快速使用Joshua的解决方案:

template <typename T>
std::ostream& operator<< (std::ostream& out, const std::vector<T>& v) {
  if ( !v.empty() ) {
    out << '[';
    std::copy (v.begin(), v.end(), std::ostream_iterator<T>(out, ", "));
    out << "\b\b]";
  }
  return out;
}
Run Code Online (Sandbox Code Playgroud)

任何其他解决方案的使用应该是直截了当的.

结论

这里介绍的任何解决方案都可行.这取决于你和一个"最好"的代码.任何比这更详细的东西最好留给另一个可以正确评估利弊的问题; 但是一如既往,用户偏好总会发挥作用:所提出的解决方案都没有错,但有些人看起来对每个编码器都更好.

附录

这是我发布的早期版本的扩展解决方案.由于该帖子一直受到关注,我决定对其进行扩展,并参考此处发布的其他优秀解决方案.我原来的职位有这样提到,如果你的一句话打算在修改里面的矢量for环路,则有提供两种方法std::vector来访问元素:std::vector::operator[]不这样做边界检查,并且std::vector::at其不执行边界检查.换句话说,at如果您尝试访问向量之外的元素而operator[]不会,则抛出.我最初只是添加了这条评论,为了提及一些可能有用的东西,知道是否有人已经没有.我现在看不出任何区别.因此这个附录.


Jos*_*itz 206

更简单的方法是使用标准复制算法:

#include <iostream>
#include <algorithm> // for copy
#include <iterator> // for ostream_iterator
#include <vector>

int main() {
    /* Set up vector to hold chars a-z */
    std::vector<char> path;
    for (int ch = 'a'; ch <= 'z'; ++ch)
        path.push_back(ch);

    /* Print path vector to console */
    std::copy(path.begin(), path.end(), std::ostream_iterator<char>(std::cout, " "));

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

ostream_iterator就是所谓的迭代器适配器.对于打印到流中的类型(在这种情况下,char)进行模板化.cout(也就是控制台输出)是我们想要写入的流,空格字符(" ")是我们想要在矢量中存储的每个元素之间打印的.

这个标准算法很强大,许多其他算法也很强大.标准库为您提供的强大功能和灵活性使其如此出色.试想:你可以打印一个矢量到控制台只有一个行代码.您不必使用分隔符来处理特殊情况.您不必担心for循环.标准库为您完成所有工作.

  • 分隔符字符串在每个元素之后写入_after_,而不是在之间,即也在最后一个之后.这可能需要处理特殊情况,如果你只想在它之间,即作为分隔符. (6认同)
  • 如果我的vector是`vector <pair <int,struct node >>`的类型怎么办?我如何使用上述方法打印此向量? (3认同)
  • @mtk你可以为你的特定对<>声明一个`operator <<函数. (2认同)

Sho*_*hoe 65

在C++ 11中,您现在可以使用基于范围的for循环:

for (auto const& c : path)
    std::cout << c << ' ';
Run Code Online (Sandbox Code Playgroud)

  • @BrianP.对.打印容器的元素不会修改容器的范围. (6认同)

Chr*_*ord 38

我认为最好的方法是operator<<通过在程序中添加此函数来重载:

#include <vector>
using std::vector;
#include <iostream>
using std::ostream;

template<typename T>
ostream& operator<< (ostream& out, const vector<T>& v) {
    out << "{";
    size_t last = v.size() - 1;
    for(size_t i = 0; i < v.size(); ++i) {
        out << v[i];
        if (i != last) 
            out << ", ";
    }
    out << "}";
    return out;
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以<<在任何可能的向量上使用运算符,假设其元素也已ostream& operator<<定义:

vector<string>  s = {"first", "second", "third"};
vector<bool>    b = {true, false, true, false, false};
vector<int>     i = {1, 2, 3, 4};
cout << s << endl;
cout << b << endl;
cout << i << endl;
Run Code Online (Sandbox Code Playgroud)

输出:

{first, second, third}
{1, 0, 1, 0, 0}
{1, 2, 3, 4}
Run Code Online (Sandbox Code Playgroud)

  • 将v.size() - 1存储为int可能会导致精度损失.我在一个被接受的同行评审编辑(http://stackoverflow.com/revisions/23397700/5)中对此进行了修复,但此后又进行了编辑,恢复了可能的精度损失.我想这在实践中并不重要,因为矢量通常不那么大. (2认同)
  • ADL找不到此运算符,因为它不在其任何参数的命名空间中。因此,它将被任何其他命名空间的`operator &lt;&lt;`隐藏。[示例](https://godbolt.org/g/nSJ6G7) (2认同)

Max*_*sca 20

for_each+ lambda表达式怎么样:

#include <vector>
#include <algorithm>
...
std::vector<char> vec;
...
std::for_each(
              vec.cbegin(),
              vec.cend(),
              [] (const char c) {std::cout << c << " ";} 
              );
...
Run Code Online (Sandbox Code Playgroud)

当然,基于范围的for是这个具体任务的最优雅的解决方案,但是这个也提供了许多其他可能性.

说明

for_each算法采用输入范围可调用对象,在范围的每个元素上调用此对象.的输入范围是由两个限定的迭代器.阿可调用对象可以是一个函数,函数指针,它重载一个类的一个对象() operator在该情况下,或作为一个λ表达式.此表达式的参数与vector中的元素类型相匹配.

这种实现的优点在于你从lambda表达式中获得的强大功能 - 你可以使用这种方法获得更多的东西,而不仅仅是打印矢量.


g24*_*24l 10

只需将容器复制到控制台即可.

std::vector<int> v{1,2,3,4};
std::copy(v.begin(),v.end(),std::ostream_iterator<int>(std::cout, " " ));
Run Code Online (Sandbox Code Playgroud)

应输出:

1 2 3 4
Run Code Online (Sandbox Code Playgroud)


MSa*_*ers 8

问题可能出在前一个循环中:(x = 17; isalpha(firstsquare); x++).此循环将根本不运行(如果firstsquare是非alpha)或将永远运行(如果它是alpha).原因是firstsquare不会随着x增加而改变.


小智 6

在C++ 11中,基于范围的for循环可能是一个很好的解决方案:

vector<char> items = {'a','b','c'};
for (char n : items)
    cout << n << ' ';
Run Code Online (Sandbox Code Playgroud)

输出:

a b c 
Run Code Online (Sandbox Code Playgroud)


dfr*_*fri 6

使用std::copy但没有额外的尾随分隔符

一种替代/修改的方法,使用std::copy(最初在@JoshuaKravtiz答案中使用),但在最后一个元素之后不包含其他尾随分隔符:

#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>

template <typename T>
void print_contents(const std::vector<T>& v, const char * const separator = " ")
{
    if(!v.empty())
    {
        std::copy(v.begin(),
                  --v.end(),
                  std::ostream_iterator<T>(std::cout, separator));
        std::cout << v.back() << "\n";
    }
}

// example usage
int main() {
    std::vector<int> v{1, 2, 3, 4};
    print_contents(v);      // '1 2 3 4'
    print_contents(v, ":"); // '1:2:3:4'
    v = {};
    print_contents(v);      // ... no std::cout
    v = {1};
    print_contents(v);      // '1'
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

应用于自定义POD类型的容器的示例用法:

// includes and 'print_contents(...)' as above ...

class Foo
{
    int i;
    friend std::ostream& operator<<(std::ostream& out, const Foo& obj);
public:
    Foo(const int i) : i(i) {}
};

std::ostream& operator<<(std::ostream& out, const Foo& obj)
{
    return out << "foo_" << obj.i; 
}

int main() {
    std::vector<Foo> v{1, 2, 3, 4};
    print_contents(v);      // 'foo_1 foo_2 foo_3 foo_4'
    print_contents(v, ":"); // 'foo_1:foo_2:foo_3:foo_4'
    v = {};
    print_contents(v);      // ... no std::cout
    v = {1};
    print_contents(v);      // 'foo_1'
    return 0;
}
Run Code Online (Sandbox Code Playgroud)


Cas*_*Cow 5

我将在这里添加另一个答案,因为我已经提出了与前一个方法不同的方法,那就是使用区域设置方面.

基础知识就在这里

基本上你做的是:

  1. 创建一个派生自的类std::locale::facet.稍微缺点是你需要一个编译单元来保存它的id.我们称之为MyPrettyVectorPrinter.你可能会给它一个更好的名字,并为对和地图创建一个.
  2. 在您的流功能中,您检查 std::has_facet< MyPrettyVectorPrinter >
  3. 如果返回true,则将其解压缩 std::use_facet< MyPrettyVectorPrinter >( os.getloc() )
  4. 您的facet对象将具有分隔符的值,您可以阅读它们.如果未找到构面,则print函数(operator<<)提供默认构面.请注意,您可以为读取矢量执行相同的操作.

我喜欢这种方法,因为您可以使用默认打印,同时仍然可以使用自定义覆盖.

如果在多个项目中使用(不仅仅是标题),还需要注意创建新语言环境对象的费用这一事实的缺点是需要一个库.

我把它写成一个新的解决方案,而不是修改我的另一个,因为我相信这两种方法都是正确的,你可以选择.


iva*_*ara 5

重载运算符<<:

template<typename OutStream, typename T>
OutStream& operator<< (OutStream& out, const vector<T>& v)
{
    for (auto const& tmp : v)
        out << tmp << " ";
    out << endl;
    return out;
}
Run Code Online (Sandbox Code Playgroud)

用法:

vector <int> test {1,2,3};
wcout << test; // or any output stream
Run Code Online (Sandbox Code Playgroud)