如何打印出vector的内容?
我想用C ++打印一个vector的内容,这里是我的:
#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; } }
如何将vector的内容打印到屏幕上?
纯粹为了回答你的问题,你可以使用一个迭代器:
std::vector<char> path; // ... for (std::vector<char>::const_iterator i = path.begin(); i != path.end(); ++i) std::cout << *i << ' ';
如果要修改for循环中的vector内容,请使用iterator
而不是const_iterator
。
但是还有很多可以说的这个。 如果你只是想要一个可以使用的答案,那么你可以在这里停下来; 否则,请继续阅读。
自动(C ++ 11)/ typedef
这不是另一个解决scheme,而是上述iterator
解决scheme的补充。 如果您使用的是C ++ 11标准(或更高版本),那么您可以使用auto
关键字来提高可读性:
for (auto i = path.begin(); i != path.end(); ++i) std::cout << *i << ' ';
但是, i
的types将是非常量(即编译器将使用std::vector<char>::iterator
作为i
的types)。
在这种情况下,你可能只需要使用typedef
(不限于C ++ 11,而且非常有用)。
typedef std::vector<char> Path; Path path; // ... for (Path::const_iterator i = path.begin(); i != path.end(); ++i) std::cout << *i << ' ';
计数器
当然,您可以使用整数types在for
循环中logging您的位置:
for(int i=0; i<path.size(); ++i) std::cout << path[i] << ' ';
如果要这样做,最好使用容器的成员types(如果可用且合适的话)。 std::vector
有一个名为size_type
的成员types用于这个作业:它是size
方法返回的types。
// Path typedef'd to std::vector<char> for( Path::size_type i=0; i<path.size(); ++i) std::cout << path[i] << ' ';
为什么不使用iterator
解决scheme呢? 对于简单的情况你可能也是如此,但重点是iterator
类是一个对象,旨在做这个工作的更复杂的对象,这个解决scheme不会是理想的。
基于范围的循环(C ++ 11)
见Jefffrey的解决scheme 。 在C ++ 11(及更高版本)中,可以使用新的基于范围的for
循环,如下所示:
for (auto i: path) std::cout << i << ' ';
由于path
是项目的向量(明确地说是std::vector<char>
),所以对象i
是向量项目的types(也就是显式地是char
types)。 对象i
有一个值是path
对象中的实际项目的副本。 因此,循环中对i
所有更改都不会保留在path
本身中。 另外,如果你想强制实现你不想在循环中改变i
的复制值,你可以强制i
的types为const char
像这样:
for (const auto i: path) std::cout << i << ' ';
如果您想修改path
的项目,可以使用参考:
for (auto& i: path) std::cout << i << ' ';
即使你不想修改path
,如果复制对象是昂贵的,你应该使用一个const引用,而不是按值复制:
for (const auto& i: path) std::cout << i << ' ';
性病::复制
见约书亚的回答 。 您可以使用STLalgorithmstd::copy
将vector内容复制到输出stream。 如果你对此感到满意,这是一个很好的解决scheme(此外,这非常有用,不仅仅是在这种情况下打印vector的内容)。
的std :: for_each的
请参阅Max的解决scheme 。 使用std::for_each
对于这个简单的场景来说是矫枉过正的,但是如果你想要做的不仅仅是打印到屏幕上,它是一个非常有用的解决scheme:使用std::for_each
允许你对vector内容进行任何 (明智的)操作。
超载ostream :: operator <<
请参阅克里斯的答案 ,这是对其他答案的补充,因为您仍然需要在重载中实现上述解决scheme之一。 在他的例子中,他在for
循环中使用了一个计数器。 例如,这就是你如何快速使用Joshua的解决scheme :
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; }
任何其他解决scheme的使用应该是直接的。
结论
任何在这里提出的解决scheme将工作。 这取决于你和哪一个是最好的代码。 比这更详细的任何事情可能是最好留下的另一个问题,正反评估可以得到适当的评估; 但是一如既往地用户偏好将始终扮演一个angular色:所提供的解决scheme都不是错误的,但是对于每个单独的编码器,一些解决scheme看起来会更好。
附录
这是我发布的早期版本的扩展解决scheme。 既然这个post一直受到关注,我决定扩展它,并参考其他在这里发布的优秀解决scheme。 我原来的post有一句话提到,如果你打算在for
循环中修改你的vector for
那么std::vector
提供了两个访问元素的方法: std::vector::operator[]
,它不会做边界检查和std::vector::at
哪个执行边界检查。 换句话说,如果你试图访问vector之外的一个元素, operator[]
就不会这样做。 原来,我只是为了提到某些事情,如果有人不知道,可能是有用的。 而我现在看到没有区别。 因此,这个附录。
更简单的方法是使用标准的复制algorithm :
#include <iostream> #include <algorithm> // for copy #include <iterator> // for ostream_iterator #include <vector> int main() { /* Set up vector to hold chars az */ 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; }
ostream_iterator就是所谓的迭代器适配器 。 它是模板化的types打印出来的stream(在这种情况下, char
)。 cout
(又名控制台输出)是我们要写入的stream,而空格字符( " "
)就是我们想要在存储在向量中的每个元素之间打印的内容。
这个标准algorithmfunction强大,其他许多function也是如此。 标准库为您提供的强大function和灵活性使得它非常棒。 试想一下:只需一行代码就可以将vector打印到控制台。 您不必使用分隔符处理特殊情况。 你不需要担心for循环。 标准的库为你做的一切。
在C ++ 11中,您现在可以使用基于范围的for循环 :
for (auto const& c : path) std::cout << c << ' ';
我认为最好的办法就是通过在程序中join这个函数来重载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; }
那么你可以在任何可能的向量上使用<<
运算符,假设它的元素也有ostream& operator<<
defined:
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;
输出:
[first, second, third] [1, 0, 1, 0, 0] [1, 2, 3, 4]
如何for_each
+ lambdaexpression式 :
#include <vector> #include <algorithm> ... std::vector<char> vec; ... std::for_each( vec.cbegin(), vec.cend(), [] (const char c) {std::cout << c << " ";} ); ...
当然,以范围为基础是这个具体任务最优雅的解决scheme,但是这个也给了很多其他的可能性。
说明
for_each
algorithm接受一个input范围和一个可调用的对象 ,在该范围的每个元素上调用该对象。 input范围由两个迭代器定义。 可调用对象可以是函数,指向函数的指针,也可以是重载() operator
的类的对象,也可以是lambdaexpression式 。 该expression式的参数与来自向量的元素的types相匹配。
这种实现的优点是你从lambdaexpression式获得的力量 – 你可以使用这种方法比打印vector更多的东西。
问题可能在前面的循环中: (x = 17; isalpha(firstsquare); x++)
。 这个循环将不会运行(如果firstsquare
是非alpha)或者将永远运行(如果它是alpha)。 原因在于x
是递增的, firstsquare
不会改变。
在C ++ 11中,基于范围的for循环可能是一个很好的解决scheme:
vector<char> items = {'a','b','c'}; for (char n : items) cout << n << ' ';
输出:a b c
我看到两个问题。 正如在for (x = 17; isalpha(firstsquare); x++)
指出的那样,如果入口字符不是'S', if (entrance == 'S')
有一个无限循环或从不执行, if (entrance == 'S')
'S'然后没有任何东西推到path向量,使其为空,因此在屏幕上什么都不打印。 您可以testing后者检查path.empty()
或打印path.size()
。
无论哪种方式,使用string代替vector不是更好吗? 您也可以像访问数组一样访问string内容,查找字符,提取子string并轻松打印string(无循环)。
用string做所有事情可能是以不太复杂的方式写出来的,更容易发现问题。
只需将容器复制到输出
std::vector<int> v{1,2,3,4}; std::copy(v.begin(),v.end(),std::ostream_iterator<int>(std::cout<< " " ));
应该输出:
1 2 3 4
超载运算符<<:
template<typename OutStream, typename T> OutStream& operator<< (OutStream& out, const vector<T>& v) { for (auto const& tmp : v) out << tmp << " "; out << endl; return out; }
用法:
vector <int> test {1,2,3}; wcout << test; // or any output stream
这个答案是基于Zorawar的答案,但我不能在那里留言。
你可以使用cbegin和cend来改变auto(C ++ 11)/ typedef的版本
for (auto i = path.cbegin(); i != path.cend(); ++i) std::cout << *i << ' ';
使用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; }
应用于自定义PODtypes的容器的示例用法:
// 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; }