我想用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;
}
}
如何将矢量内容打印到屏幕上?
纯粹回答你的问题,你可以使用迭代器:
std::vector<char> path;
// ...
for (std::vector<char>::const_iterator i = path.begin(); i != path.end(); ++i)
std::cout << *i << ' ';
如果你想在for循环中修改向量的内容,那么使用iterator
而不是const_iterator
。
但是关于这一点可以说更多。如果您只想要一个可以使用的答案,那么您可以在这里停下来;否则,请继续阅读。
这不是另一种解决方案,而是对上述iterator
解决方案的补充。如果您使用的是C ++ 11标准(或更高版本),则可以使用auto
关键字来帮助提高可读性:
for (auto i = path.begin(); i != path.end(); ++i)
std::cout << *i << ' ';
但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 << ' ';
当然,您可以使用整数类型在for
循环中记录您的位置:
for(int i=0; i<path.size(); ++i)
std::cout << path[i] << ' ';
如果要执行此操作,最好使用容器的成员类型(如果它们可用且适当)。 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] << ' ';
为什么不在iterator
解决方案上使用它呢?对于简单的情况,您也可以这样做,但重点是iterator
类是一个对象,旨在为更复杂的对象完成此工作,而这个解决方案并不理想。
见Jefffrey's solution。在C ++ 11(及更高版本)中,您可以使用新的基于范围的for
循环,如下所示:
for (auto i: path)
std::cout << i << ' ';
由于path
是项目的向量(明确地为std::vector<char>
),因此对象i
是向量项的类型(即,显式地,它是char
类型)。对象i
的值是path
对象中实际项的副本。因此,i
本身并未保留对循环中path
的所有更改。此外,如果您想强制执行以下事实:您不希望能够在循环中更改i
的复制值,则可以强制i
的类型为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 << ' ';
见Joshua's answer。您可以使用STL算法std::copy
将矢量内容复制到输出流。如果您对它感到满意,这是一个优雅的解决方案(此外,它非常有用,不仅仅是在打印矢量内容的情况下)。
见Max's solution。使用std::for_each
对于这个简单的场景来说太过分了,但是如果你想做的不仅仅是打印到屏幕上,它是一个非常有用的解决方案:使用std::for_each
可以对矢量内容进行任何(合理的)操作。
请参阅Chris's answer,这是对其他答案的补充,因为您仍需要在重载中实现上述解决方案之一。在他的例子中,他在for
循环中使用了一个计数器。例如,这就是你如何快速使用Joshua's solution:
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;
}
任何其他解决方案的使用应该是直截了当的。
这里介绍的任何解决方案都可行。这取决于你和一个“最好”的代码。任何比这更详细的东西最好留给另一个可以正确评估利弊的问题;但是一如既往,用户偏好总会发挥作用:所提出的解决方案都没有错,但有些人看起来对每个编码器都更好。
这是我发布的早期版本的扩展解决方案。由于该帖子一直受到关注,我决定对其进行扩展,并参考此处发布的其他优秀解决方案。我的原帖有一句话提到,如果你打算在for
循环中修改你的向量,那么std::vector
提供两种方法来访问元素:std::vector::operator[]
不进行边界检查,std::vector::at
进行边界检查。换句话说,如果你试图访问向量之外的元素而at
将不会抛出operator[]
。我最初只是添加了这条评论,为了提及一些可能有用的东西,知道是否有人已经没有。我现在看不出任何区别。因此这个附录。
我看到两个问题。正如在for (x = 17; isalpha(firstsquare); x++)
中所指出的,要么是无限循环,要么根本没有执行,如果入口字符与'S'不同,那么在if (entrance == 'S')
中没有任何东西被推到路径向量中,使其变空并因此在屏幕上不打印。您可以测试后者检查path.empty()
或打印path.size()
。
无论哪种方式,使用字符串而不是向量不是更好吗?您也可以像数组一样访问字符串内容,搜索字符,提取子字符串并轻松打印字符串(没有循环)。
用字符串完成所有操作可能是以较少复杂的方式编写它并更容易发现问题的方法。
重载运算符<<:
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版本const
for (auto i = path.cbegin(); i != path.cend(); ++i)
std::cout << *i << ' ';
在C ++ 11``中
for (auto i = path.begin(); i != path.end(); ++i)
std::cout << *i << ' ';
for(int i=0; i<path.size(); ++i)
std::cout << path[i] << ' ';
你可以编写自己的函数:
void printVec(vector<char> vec){
for(int i = 0; i < vec.size(); i++){
cout << vec[i] << " ";
}
cout << endl;
}
#include<bits/stdc++.h>
using namespace std;
int main()
{
vector <pair<string,int> > v;
int n;
cin>>n;
int i;
for( i=0;i<n;i++)
{
int end;
string str;
cin>>str;
cin>>end;
v.push_back(make_pair(str,end));
}
for (int j=0;j<n;j++)
{
cout<<v[j].first<< " "<<v[j].second<<endl;
}``
}
这对我有用:
for (auto& i : name)
{
int r = 0;
for (int j = 0; j < name[r].size();j++)
{
std::cout << i[j];
}
r++;
std::cout << std::endl;
}
更简单的方法是使用标准的copy algorithm:
#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;
}
ostream_iterator就是所谓的迭代器适配器。对于打印到流中的类型(在这种情况下,char
)进行模板化。 cout
(又名控制台输出)是我们想要写入的流,空格字符(" "
)是我们想要在矢量中存储的每个元素之间打印的。
这个标准算法很强大,许多其他算法也很强大。标准库为您提供的强大功能和灵活性使其如此出色。试想一下:只需一行代码即可将矢量打印到控制台。您不必使用分隔符来处理特殊情况。您不必担心for循环。标准库为您完成所有工作。
在C ++ 11中,您现在可以使用range-based for loop:
for (auto const& c : path)
std::cout << c << ' ';
我认为最好的方法是通过在程序中添加此函数来重载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<<
:
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
+ lambda表达式:
#include <vector>
#include <algorithm>
...
std::vector<char> vec;
...
std::for_each(
vec.cbegin(),
vec.cend(),
[] (const char c) {std::cout << c << " ";}
);
...
当然,基于范围的for是这个具体任务的最优雅的解决方案,但是这个也提供了许多其他可能性。
说明
for_each
算法采用输入范围和可调用对象,在范围的每个元素上调用此对象。输入范围由两个迭代器定义。可调用对象可以是函数,指向函数的指针,重载() operator
的类的对象,或者在本例中是lambda表达式。此表达式的参数与vector中的元素类型相匹配。
这种实现的优点在于你从lambda表达式中获得的强大功能 - 你可以使用这种方法获得更多的东西,而不仅仅是打印矢量。
只需将容器复制到控制台即可。
std::vector<int> v{1,2,3,4};
std::copy(v.begin(),v.end(),std::ostream_iterator<int>(std::cout, " " ));
应输出:
1 2 3 4
问题可能出在前一个循环中:(x = 17; isalpha(firstsquare); x++)
。这个循环根本不运行(如果firstsquare
是非alpha)或将永远运行(如果它是alpha)。原因是当firstsquare
增加时,x
不会改变。
在C ++ 11中,基于范围的for循环可能是一个很好的解决方案:
vector<char> items = {'a','b','c'};
for (char n : items)
cout << n << ' ';
输出:
a b c
std::copy
but without extra trailing separator使用std::copy
(最初在@JoshuaKravtiz answer中使用)的替代/修改方法,但在最后一个元素之后不包括额外的尾随分隔符:
#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;
}
应用于自定义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;
}