我想用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;
}
}
如何将矢量内容打印到屏幕上?
答案 0 :(得分:323)
纯粹回答你的问题,你可以使用迭代器:
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
是向量项的类型(即,显式地,它的类型为{{ 1}})。对象char
的值为i
对象中实际项的副本。因此,循环中path
的所有更改都不会保留在i
本身中。此外,如果您希望强制执行以下事实:您不希望在循环中更改path
的复制值,则可以强制i
的类型为{{1像这样:
i
如果您想修改const char
中的项目,可以使用参考:
for (const auto i: path)
std::cout << i << ' ';
即使你不想修改path
,如果复制对象很昂贵,你应该使用const引用而不是按值复制:
for (auto& i: path)
std::cout << i << ' ';
见Joshua's answer。您可以使用STL算法path
将矢量内容复制到输出流。如果您对它感到满意,这是一个优雅的解决方案(此外,非常有用,不仅仅是在打印矢量内容的情况下)。
见Max's solution。使用for (const auto& i: path)
std::cout << i << ' ';
对于这个简单的场景来说太过分了,但如果你想做的不仅仅是打印到屏幕上,它是一个非常有用的解决方案:使用std::copy
可以让你做任何 (明智的)对矢量内容的操作。
请参阅Chris's answer,这是对其他答案的补充,因为您仍需要在重载中实现上述解决方案之一。在他的例子中,他在std::for_each
循环中使用了一个计数器。例如,您可以快速使用Joshua's solution:
std::for_each
任何其他解决方案的使用应该是直截了当的。
此处介绍的任何解决方案均可使用。这取决于你和一个“最好”的代码。任何比这更详细的东西最好留给另一个可以正确评估利弊的问题;但是一如既往,用户偏好总会发挥作用:所提出的解决方案都没有错,但有些人会对每个编码器看起来更好。
这是我发布的早期版本的扩展解决方案。由于该帖子一直受到关注,我决定对其进行扩展,并参考此处发布的其他优秀解决方案。我的原帖有一句话提到,如果 打算在for
循环中修改你的向量,那么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;
}
提供两种方法来访问元素:{{ 1}}不执行边界检查,for
执行边界检查。换句话说,如果您尝试访问向量之外的元素而std::vector
不会,则std::vector::operator[]
将抛出。我最初只是添加了这条评论,为了提及一些可能有用的东西,知道是否有人已经没有。我现在看不出任何区别。因此这个附录。
答案 1 :(得分:199)
更简单的方法是使用标准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循环。标准库为您完成所有工作。
答案 2 :(得分:64)
在C ++ 11中,您现在可以使用range-based for loop:
for (auto const& c : path)
std::cout << c << ' ';
答案 3 :(得分:37)
我认为最好的方法是通过在程序中添加此函数来重载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}
答案 4 :(得分:18)
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_each
算法采用输入范围和可调用对象,在范围的每个元素上调用此对象。 输入范围由两个迭代器定义。 可调用对象可以是一个函数,一个指向函数的指针,一个重载() operator
的类的对象,或者在这种情况下,一个lambda表达式。此表达式的参数与vector中的元素类型相匹配。
这种实现的优点在于你从lambda表达式中获得的力量 - 除了打印向量之外,你可以使用这种方法来做更多的事情。
答案 5 :(得分:8)
问题可能出在前一个循环中:(x = 17; isalpha(firstsquare); x++)
。这个循环根本不会运行(如果firstsquare
是非alpha)或将永远运行(如果它是alpha)。原因是firstsquare
在x
递增时不会改变。
答案 6 :(得分:8)
只需将容器复制到控制台即可。
std::vector<int> v{1,2,3,4};
std::copy(v.begin(),v.end(),std::ostream_iterator<int>(std::cout, " " ));
应输出:
1 2 3 4
答案 7 :(得分:6)
在C ++ 11中,基于范围的for循环可能是一个很好的解决方案:
vector<char> items = {'a','b','c'};
for (char n : items)
cout << n << ' ';
输出:
a b c
答案 8 :(得分:4)
child-2
但没有额外的尾随分隔符使用std::copy
的替代/修改方法(最初在@JoshuaKravtiz answer中使用)但在最后一个元素之后不包括额外的尾随分隔符:
parent
应用于自定义POD类型容器的示例用法:
std::copy
答案 9 :(得分:3)
我看到两个问题。正如在for (x = 17; isalpha(firstsquare); x++)
中指出的那样,无论是无限循环还是根本不执行,如果入口角色不同于if (entrance == 'S')
,则path.empty()
也是如此。然后没有任何东西被推到路径向量,使其为空,因此在屏幕上不打印任何内容。您可以测试后者检查path.size()
或打印{{1}}。
无论哪种方式,使用字符串而不是向量都不会更好吗?您也可以像数组一样访问字符串内容,查找字符,提取子字符串并轻松打印字符串(无循环)。
使用字符串完成所有操作可能是以较少复杂的方式编写它并更容易发现问题的方法。
答案 10 :(得分:3)
这个答案是基于Zorawar的答案,但我无法在那里发表评论。
您可以使用cbegin和cend来生成auto(C ++ 11)/ typedef版本的const
for (auto i = path.cbegin(); i != path.cend(); ++i)
std::cout << *i << ' ';
答案 11 :(得分:3)
重载运算符&lt;&lt;:
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
答案 12 :(得分:1)
在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] << ' ';
答案 13 :(得分:0)
您可以编写自己的函数:
void printVec(vector<char> vec){
for(int i = 0; i < vec.size(); i++){
cout << vec[i] << " ";
}
cout << endl;
}
答案 14 :(得分:0)
#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;
}``
}
答案 15 :(得分:0)
这对我有用:
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;
}
答案 16 :(得分:0)
对于那些感兴趣的人:我写了一个通用的解决方案,它兼顾了两个方面的优点,更广泛地适用于任何类型的范围,并在非算术类型(如字符串型类型)周围加引号。此外,这种方法不应有任何ADL问题,并且还应避免“意外”(因为它是根据具体情况明确添加的):
template <typename T>
inline constexpr bool is_string_type_v = std::is_convertible_v<const T&, std::string_view>;
template<class T>
struct range_out {
range_out(T& range) : r_(range) {
}
T& r_;
static_assert(!::is_string_type_v<T>, "strings and string-like types should use operator << directly");
};
template <typename T>
std::ostream& operator<< (std::ostream& out, range_out<T>& range) {
constexpr bool is_string_like = is_string_type_v<T::value_type>;
constexpr std::string_view sep{ is_string_like ? "', '" : ", " };
if (!range.r_.empty()) {
out << (is_string_like ? "['" : "[");
out << *range.r_.begin();
for (auto it = range.r_.begin() + 1; it != range.r_.end(); ++it) {
out << sep << *it;
}
out << (is_string_like ? "']" : "]");
}
else {
out << "[]";
}
return out;
}
现在在任何范围内都非常容易使用:
std::cout << range_out{ my_vector };
类似字符串的检查留有改进的余地。
我也确实有static_assert
签入解决方案来避免使用std::basic_string<>
,但是为了简单起见,在此省略了它。
答案 17 :(得分:0)
std::cout <<
和std::to_string
std::vector
,std::array
和std::tuple
由于在cpp中打印矢量结果出乎意料的繁重工作(至少与该任务的基本操作相比),并且在与其他容器一起工作时,又一次跨过同一问题,这是一个更通用的解决方案。
此模板集合处理3种容器类型:
std::vector
,std::array
和std::tuple
。
它为这些定义了std::to_string()
,并可以通过std::cout << container;
直接将它们打印出来。
此外,它为std::string << container
定义了<<操作符。
这样,就可以以紧凑的方式构造包含这些容器类型的字符串。
来自
std::string s1 = "s1: " + std::to_string(arr) + "; " + std::to_string(vec) + "; " + std::to_string(tup);
我们去
std::string s2 = STR() << "s2: " << arr << "; " << vec << "; " << tup;
您可以以交互方式测试此代码:here。
#include <iostream>
#include <string>
#include <tuple>
#include <vector>
#include <array>
namespace std
{
// declations: needed for std::to_string(std::vector<std::tuple<int, float>>)
std::string to_string(std::string str);
std::string to_string(const char *str);
template<typename T, size_t N>
std::string to_string(std::array<T, N> const& arr);
template<typename T>
std::string to_string(std::vector<T> const& vec);
template<typename... Args>
std::string to_string(const std::tuple<Args...>& tup);
std::string to_string(std::string str)
{
return std::string(str);
}
std::string to_string(const char *str)
{
return std::string(str);
}
template<typename T, size_t N>
std::string to_string(std::array<T, N> const& arr)
{
std::string s="{";
for (std::size_t t = 0; t != N; ++t)
s += std::to_string(arr[t]) + (t+1 < N ? ", ":"");
return s + "}";
}
template<typename T>
std::string to_string(std::vector<T> const& vec)
{
std::string s="[";
for (std::size_t t = 0; t != vec.size(); ++t)
s += std::to_string(vec[t]) + (t+1 < vec.size() ? ", ":"");
return s + "]";
}
// to_string(tuple)
// https://en.cppreference.com/w/cpp/utility/tuple/operator%3D
template<class Tuple, std::size_t N>
struct TupleString
{
static std::string str(const Tuple& tup)
{
std::string out;
out += TupleString<Tuple, N-1>::str(tup);
out += ", ";
out += std::to_string(std::get<N-1>(tup));
return out;
}
};
template<class Tuple>
struct TupleString<Tuple, 1>
{
static std::string str(const Tuple& tup)
{
std::string out;
out += std::to_string(std::get<0>(tup));
return out;
}
};
template<typename... Args>
std::string to_string(const std::tuple<Args...>& tup)
{
std::string out = "(";
out += TupleString<decltype(tup), sizeof...(Args)>::str(tup);
out += ")";
return out;
}
} // namespace std
/**
* cout: cout << continer
*/
template <typename T, std::size_t N> // cout << array
std::ostream& operator <<(std::ostream &out, std::array<T, N> &con)
{
out << std::to_string(con);
return out;
}
template <typename T, typename A> // cout << vector
std::ostream& operator <<(std::ostream &out, std::vector<T, A> &con)
{
out << std::to_string(con);
return out;
}
template<typename... Args> // cout << tuple
std::ostream& operator <<(std::ostream &out, std::tuple<Args...> &con)
{
out << std::to_string(con);
return out;
}
/**
* Concatenate: string << continer
*/
template <class C>
std::string operator <<(std::string str, C &con)
{
std::string out = str;
out += std::to_string(con);
return out;
}
#define STR() std::string("")
int main()
{
std::array<int, 3> arr {1, 2, 3};
std::string sArr = std::to_string(arr);
std::cout << "std::array" << std::endl;
std::cout << "\ttest to_string: " << sArr << std::endl;
std::cout << "\ttest cout <<: " << arr << std::endl;
std::cout << "\ttest string <<: " << (std::string() << arr) << std::endl;
std::vector<std::string> vec {"a", "b"};
std::string sVec = std::to_string(vec);
std::cout << "std::vector" << std::endl;
std::cout << "\ttest to_string: " << sVec << std::endl;
std::cout << "\ttest cout <<: " << vec << std::endl;
std::cout << "\ttest string <<: " << (std::string() << vec) << std::endl;
std::tuple<int, std::string> tup = std::make_tuple(5, "five");
std::string sTup = std::to_string(tup);
std::cout << "std::tuple" << std::endl;
std::cout << "\ttest to_string: " << sTup << std::endl;
std::cout << "\ttest cout <<: " << tup << std::endl;
std::cout << "\ttest string <<: " << (std::string() << tup) << std::endl;
std::vector<std::tuple<int, float>> vt {std::make_tuple(1, .1), std::make_tuple(2, .2)};
std::string sVt = std::to_string(vt);
std::cout << "std::vector<std::tuple>" << std::endl;
std::cout << "\ttest to_string: " << sVt << std::endl;
std::cout << "\ttest cout <<: " << vt << std::endl;
std::cout << "\ttest string <<: " << (std::string() << vt) << std::endl;
std::cout << std::endl;
std::string s1 = "s1: " + std::to_string(arr) + "; " + std::to_string(vec) + "; " + std::to_string(tup);
std::cout << s1 << std::endl;
std::string s2 = STR() << "s2: " << arr << "; " << vec << "; " << tup;
std::cout << s2 << std::endl;
return 0;
}
std::array
test to_string: {1, 2, 3}
test cout <<: {1, 2, 3}
test string <<: {1, 2, 3}
std::vector
test to_string: [a, b]
test cout <<: [a, b]
test string <<: [a, b]
std::tuple
test to_string: (5, five)
test cout <<: (5, five)
test string <<: (5, five)
std::vector<std::tuple>
test to_string: [(1, 0.100000), (2, 0.200000)]
test cout <<: [(1, 0.100000), (2, 0.200000)]
test string <<: [(1, 0.100000), (2, 0.200000)]
s1: {1, 2, 3}; [a, b]; (5, five)
s2: {1, 2, 3}; [a, b]; (5, five)
答案 18 :(得分:0)
如果 boost 是一个选项,那么您可以使用 boost::algorithm::join
。例如打印出 std::string
的向量:
#include <boost/algorithm/string/join.hpp>
std::vector<std::string> vs { "some", "string", "vector" };
std::cout << boost::algorithm::join(vs, " | ") << '\n';
对于其他类型的向量,您需要先 transform 字符串
#include <algorithm>
#include <iostream>
#include <numeric>
#include <vector>
#include <boost/algorithm/string/join.hpp>
#include <boost/range/adaptor/transformed.hpp>
int main()
{
using boost::adaptors::transformed;
using boost::algorithm::join;
// Generate the vector
std::vector<int> vi(10);
std::iota(vi.begin(), vi.end(), -3);
// Print out the vector
std::cout << join(vi |
transformed(static_cast<std::string(*)(int)>(std::to_string)),
", ")
<< '\n';
}
答案 19 :(得分:0)
您可以使用std::experimental::make_ostream_joiner
:
#include <algorithm>
#include <experimental/iterator>
#include <iostream>
#include <iterator>
#include <numeric>
#include <vector>
int main()
{
std::vector<int> vi(12);
std::iota(vi.begin(), vi.end(), -5);
std::cout << "Int vector:\n";
std::copy(std::begin(vi),
std::end(vi),
std::experimental::make_ostream_joiner(std::cout, ", "));
std::cout <<"\nString vector:\n[";
std::vector<std::string> vs { "some", "string", "vector" };
std::copy(std::begin(vs),
std::end(vs),
std::experimental::make_ostream_joiner(std::cout, "] - ["));
std::cout << "]\n";
}
答案 20 :(得分:-1)
对于希望单线无循环的人:
我不敢相信没有人会这样做,但这也许是因为它更像C。无论如何,在一个循环中假设 std::vector<char>
为空终止的情况下,无循环地进行此操作是绝对安全的:
std::vector<char> test { 'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!', '\0' };
std::cout << test.data() << std::endl;
但是为了安全起见,我会按照@Zorawar的建议将其包装在ostream
运算符中:
template <typename T>std::ostream& operator<< (std::ostream& out, std::vector<T>& v)
{
v.push_back('\0'); // safety-check!
out << v.data();
return out;
}
std::cout << test << std::endl; // will print 'Hello, world!'
我们可以通过使用printf
来实现类似的行为:
fprintf(stdout, "%s\n", &test[0]); // will also print 'Hello, world!'
注意:
重载的ostream
运算符需要将向量接受为非常量。这可能会使程序不安全或引入错误的代码。另外,由于附加了空字符,因此可能发生std::vector
的重新分配。因此,使用带有迭代器的for循环可能会更快。