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ループでベクターのコンテンツを変更する場合は、const_iterator
ではなくiterator
を使用します。
しかし、これについて言えることは他にもたくさんあります。使用できる答えだけが必要な場合は、ここで停止できます。それ以外の場合は、読んでください。
これは別のソリューションではありませんが、上記のiterator
ソリューションの補足です。 C++ 11標準(またはそれ以降)を使用している場合は、auto
キーワードを使用して読みやすくすることができます。
for (auto i = path.begin(); i != path.end(); ++i)
std::cout << *i << ' ';
ただし、i
の型は非定数です(つまり、コンパイラはi
の型としてstd::vector<char>::iterator
を使用します)。
この場合は、typedef
を使用することもできます(C++ 11に限定されず、veryとにかく便利です) :
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の解 を参照してください。 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 << ' ';
ジョシュアの答え を参照してください。 STLアルゴリズムstd::copy
を使用して、ベクターコンテンツを出力ストリームにコピーできます。これは、慣れている場合はエレガントなソリューションです(さらに、ベクトルの内容を印刷する場合だけでなく、very便利です) )。
Maxの解 を参照してください。 std::for_each
の使用はこの単純なシナリオでは過剰ですが、スクリーンに印刷するだけでなく、それ以外のことをしたい場合には非常に便利なソリューションです。std::for_each
を使用すると、 any (賢明な)操作ベクトルの内容。
Chris's answer を参照してください。これは、オーバーロードで上記のソリューションのいずれかを実装する必要があるため、他の回答を補完するものです。彼の例では、彼は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;
}
他のソリューションの使用方法は簡単です。
ここに示されているソリューションはどれでも機能します。それはあなたと、それが「最良」であるコード次第です。これよりも詳細な点は、賛否両論を適切に評価できる別の質問に残しておくとよいでしょう。しかし、いつものように、ユーザーの好みは常に役割を果たします。提示された解決策はどれも間違っていませんが、個々のコーダーにとってより見栄えの良いものもあります。
これは、以前に投稿したソリューションを拡張したソリューションです。その投稿が注目を集めていたので、私はそれを拡張し、ここに投稿された他の優れたソリューションを参照することにしました。私の元の投稿には、 were を[for
ループ内でベクトルを変更する場合、要素にアクセスするstd::vector
によって提供される2つのメソッドがあります:std::vector::operator[]
境界チェックを行いません。std::vector::at
は境界チェックを行います。つまり、ベクトルの外部の要素にアクセスしようとしてもoperator[]
がアクセスしない場合、at
はスローされます。元々このコメントを追加したのは、誰かが既に知らなかった場合に知っておくと役立つかもしれないことを言及するためです。そして今、私は違いが見られません。したがって、この補遺。
もっと簡単な方法は、標準の コピーアルゴリズムを使うことです :
#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はiterator adapterと呼ばれるものです。それはストリームに出力するために型をテンプレート化したものです(この場合はchar
)。 cout
(別名コンソール出力)は書き込みたいストリームで、スペース文字(" "
)はベクトルに格納された各要素の間に表示したいものです。
この標準アルゴリズムは強力で、他にもたくさんあります。標準ライブラリがあなたに与える力と柔軟性はそれをそれほど素晴らしいものにします。想像してみてください。 one のコード行でベクトルをコンソールに表示できます。区切り文字を使って特別な場合を扱う必要はありません。 forループについて心配する必要はありません。標準ライブラリはあなたのためにそれをすべて行います。
C++ 11では、 範囲ベースのforループ :を使用できます。
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
+ラムダ式 :
#include <vector>
#include <algorithm>
...
std::vector<char> vec;
...
std::for_each(
vec.cbegin(),
vec.cend(),
[] (const char c) {std::cout << c << " ";}
);
...
もちろん、 の範囲ベースの はこの具体的な作業のための最も洗練された解決策ですが、これも他の多くの可能性を与えます。
説明
for_each
アルゴリズムは 入力範囲 と 呼び出し可能オブジェクト を取り、このオブジェクトを範囲のすべての要素で呼び出します。 入力範囲 は、2つの イテレータ によって定義されます。 呼び出し可能オブジェクト は、関数、関数へのポインタ、() operator
をオーバーロードするクラスのオブジェクト、またはこの場合のように ラムダ式 のいずれかです。この式のパラメータはvectorの要素の型と一致します。
この実装の利点は、ラムダ式から得られるパワーです。ベクトルを印刷するだけでなく、このアプローチをもっと多くのことに使用できます。
コンテナーをコンソールにコピーするだけです。
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
が非アルファの場合)、または永久に実行されます(アルファの場合)。その理由は、firstsquare
が増加してもx
は変化しないからです。
C++ 11では、範囲ベースのforループが良い解決策かもしれません。
vector<char> items = {'a','b','c'};
for (char n : items)
cout << n << ' ';
出力:
a b c
std::copy
を使用しますが、追加の末尾の区切り記号は使用しません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;
}
オーバーロード演算子<<:
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
2つ問題があります。 for (x = 17; isalpha(firstsquare); x++)
で指摘されているように、無限ループがあるかまったく実行されないか、またif (entrance == 'S')
では入口文字が 'S'と異なる場合は何もパスベクトルにプッシュされず、空になり画面に何も表示しません。後者のpath.empty()
のチェックやpath.size()
の出力をテストすることができます。
どちらの方法でも、ベクトルの代わりに文字列を使用するほうが良いでしょうか。配列のように文字列の内容にアクセスしたり、文字を探したり、部分文字列を抽出したり、文字列を簡単に印刷したりできます(ループなし)。
すべて文字列でそれを行うことは、それを複雑でない方法で書いて問題を見つけやすくするための方法かもしれません。
この回答は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] << ' ';
これは私のために働いた:
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;
}
#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;
}``
}
あなたはあなた自身の関数を書くことができます:
void printVec(vector<char> vec){
for(int i = 0; i < vec.size(); i++){
cout << vec[i] << " ";
}
cout << endl;
}
興味のある人のために:私は両方の長所を活用し、あらゆるタイプの範囲により一般化され、非算術タイプ(文字列のようなタイプに望ましい)を引用符で囲む一般化されたソリューションを書きました。さらに、このアプローチには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<>
チェックインもしていますが、簡単にするためにここでは省略しました。