ベクターの内容を印刷する方法は?


281

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;
    }
}

ベクターの内容を画面に出力するにはどうすればよいですか?


1
なぜ「機能しない」のですか?
デフォルトの

回答:


392

純粋にあなたの質問に答えるために、あなたはイテレータを使うことができます:

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

forループでベクターの内容を変更する場合は、iteratorではなくを使用してくださいconst_iterator

しかし、これについて言えることはもっとたくさんあります。使用できる答えだけが必要な場合は、ここで停止できます。それ以外の場合は読み続けてください。

自動(C ++ 11)/ typedef

これは別のソリューションではなく、上記のiteratorソリューションの補足です。C ++ 11標準(またはそれ以降)を使用している場合は、autoキーワードを使用して読みやすくすることができます。

for (auto i = path.begin(); i != path.end(); ++i)
    std::cout << *i << ' ';

ただし、のタイプはi非定数になります(つまり、コンパイラは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クラスは、このソリューションが理想的ではない、より複雑なオブジェクトに対してこの仕事をするように設計されたオブジェクトであることです。

範囲ベースのforループ(C ++ 11)

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 << ' ';

std :: copy

ジョシュアの答えを見てください。STLアルゴリズムを使用できますstd::copyを、ベクトルの内容を出力ストリームにコピーます。これは、慣れていればエレガントなソリューションです(しかも、ベクトルの内容を印刷する場合だけでなく、非常に便利です)。

std :: for_each

Maxのソリューションを参照してください。std::for_eachこの単純なシナリオでは、使用はやり過ぎですが、画面に出力するだけではない場合は、非常に便利なソリューションです。使用std::for_eachすると、ベクターコンテンツに対して任意の(賢明な)操作を実行できます。

オーバーロードostream :: operator <<

クリスの回答を参照してください。これは、オーバーロードで上記のソリューションの1つを実装する必要があるため、他の回答をさらに補完するものです。彼の例では、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;
}

他のソリューションの使用は簡単です。

結論

ここで紹介するソリューションはどれも機能します。それはあなたと1つが「最高」であるコード次第です。これよりも詳細なことは、おそらく賛否両論を適切に評価できる別の質問に任せるのが最善です。しかし、いつものように、ユーザーの好みが常に役割を果たすでしょう:提示された解決策のどれも間違っていませんが、いくつかは個々のコーダーに見栄えがします。

補遺

これは、以前に投稿したソリューションの拡張ソリューションです。その投稿が注目を集め続けているので、私はそれを拡張して、ここに投稿された他の優れたソリューションを参照することにしました。私のオリジナルのポストは、あなたがあればそれを言及した発言だったし、内部のあなたのベクトルの変更に意図forそこが提供する2つの方法ですループをstd::vector:アクセス要素にstd::vector::operator[]境界チェックしません、とstd::vector::atした境界チェックを行います。言い換えれば、atベクトルの外側の要素にアクセスしようとしてもアクセスしない場合にスローされますoperator[]。元々、私がこのコメントを追加したのは、誰かがまだしなかった場合に知っておくと役立つかもしれないことを説明するためです。そして、私は今、違いはありません。したがって、この補遺。


ループし0ていvector::size()て、ベクトルがループ内で変更されていない場合は、使用at()して境界チェックのオーバーヘッドを追加する必要はありません。そうは言っても、あなたが提案するように私はイテレータを使います。
Ed S.

1
@Ed:ええ、そこに使用してもポイントのないatループ修正に何もあれば、ベクターは、私は、私は念のために、ベクターは、それを言及しようと思いましているループ内で変更された(それはあるかもしれないとして推奨されない)、それはAを取得したことがないので、言及し、少なくともそれを知ることは有用かもしれません。
Zorawar 2012

次のように範囲ベースのforループは、大サブオブジェクトの場合に重要であり得る使用参考文献に書き換えることができる:for (auto const &i: path) std::cout << i << ' ';
underscore_d

@underscore_d:ありがとう。そのセクションを整理しました。これで、より完全で少し明確になったことを願っています。
Zorawar

「overload operator <<」は良い解決策ではありません。引数に依存するルックアップのため、オーバーロードされた演算子の少なくとも1つのオペランドはプログラムで定義されたクラスである必要があります
MM

218

これを行うはるかに簡単な方法は、標準のコピーアルゴリズムを使用することです

#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(別名コンソール出力)は書き込み先のストリームであり、スペース文字(" ")はベクターに格納されている各要素の間に出力するものです。

この標準アルゴリズムは強力であり、他の多くのアルゴリズムも同様です。標準ライブラリがもたらすパワーと柔軟性は、それを非常に優れたものにします。想像してみてください。1行のコードでコンソールにベクトルを出力できます。区切り文字を使用して特殊なケースを処理する必要はありません。forループについて心配する必要はありません。標準ライブラリはあなたのためにそれをすべて行います。


3
何を私のベクトルはタイプであった場合vector<pair<int, struct node>>。上記の方法を使用してこのベクターを印刷するにはどうすればよいですか?
mtk

6
区切り文字列は、要素間ではなく、つまり最後の要素の後にも書き込まれます。セパレータとしてのみ使用したい場合は、特殊なケースに対処する必要があります。
Quigi、2015

2
@mtkを使用するoperator<<と、特定のペアの関数を宣言できます<>。
ShoeLace 2017年

同様のアプローチを示す回答を追加しましが、余分な末尾の区切り文字に関して、上記の@Quigi:sコメントを考慮に入れました。
dfri 2017

@ShoeLace他に方法はありませんか?
thegreatcoder

69

C ++ 11では、範囲ベースのforループを使用できるようになりました。

for (auto const& c : path)
    std::cout << c << ' ';

これは、ループの範囲の本体でベクトルのサイズが変更されていない場合にのみ機能します。
ブライアン

8
@BrianP。うん。コンテナの要素を印刷しても、コンテナの範囲は変更されません。

ここで望ましいのは–値のコピーとして、または要素のコピーを回避するためのconst参照としてのc?
kleinfreund、2015年

@kleinfreundベクトルの内容によって異なります。たとえば、charsのベクトルの場合、定数参照による受け渡しは、実際には値による受け渡しよりもコストがかかる可能性があります。しかし、ここでは超ミクロ最適化について話しています。

43

これを行う最良の方法は、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}

3
v.size()-1をintとして格納すると、精度が失われる可能性があります。承認されたピアレビューの編集(stackoverflow.com/revisions/23397700/5)でこれを修正しましたが、その後、精度が失われる可能性を復元するために再度編集されました。ベクトルは通常それほど大きくないので、実際にはそれほど重要ではないと思います。
JDiMatteo 2014年

変数として保存しないと、コードの可読性が低下します。これは、私が同意しなかった編集の一部です。のタイプをlastに変更しましたsize_t
Chris Redford

size_t last = v.size() - 1;冗長に見えますが、リンクif (i) out << ", ";前の条件を使用できますout << v[i];
Vladimir Gamalyan '30

3
この演算子は、その引数の名前空間にないため、ADLでは見つかりません。したがって、他のネームスペースによって非表示になりますoperator<<
MM

これを行うつもりなら、なぜループのif (i != last) たびテストするのですか?代わりに、コンテナが空でない場合は、(a)最初の要素を送信し、(b)残りの要素をループ送信して 、セパレータを最初に(接頭辞として)印刷します。(ループ条件自体は別として)内部ループテストは必要ありません。ループ外テストは1つだけ必要です。
WhozCraig

22

いかがfor_each+ラムダ式

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

もちろん、範囲ベースのforは、この具体的なタスクの最もエレガントなソリューションですが、これは他の多くの可能性も提供します。

説明

for_eachこのアルゴリズムは、かかる入力範囲呼び出し可能オブジェクトの範囲のすべての要素にこのオブジェクトを呼び出して、。入力範囲は 2つので定義されるイテレータ呼び出し可能なオブジェクトは、関数、関数へのポインタ、どのオーバーロードクラスのオブジェクトであることができる() operatorか、この場合のように、ラムダ式。この式のパラメーターは、ベクトルの要素のタイプと一致します。

この実装の美しさは、ラムダ式から得られる力です。この方法は、ベクトルを出力するだけではなく、さまざまな目的で使用できます。


10

コンテナーをコンソールにコピーするだけです。

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

出力する必要があります:

1 2 3 4

8

問題はおそらく前のループにあります:(x = 17; isalpha(firstsquare); x++)。このループはまったく実行されないか(firstsquareアルファでない場合)、または永久に実行されます(アルファの場合)。その理由は、インクリメントさfirstsquareれても変化しないからxです。


7

C ++ 11では、範囲ベースのforループが適切な解決策になる場合があります。

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

出力:

a b c 

6

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;
}

3

2つの問題が発生します。for (x = 17; isalpha(firstsquare); x++)無限ループがあるかまったく実行されないこと、およびif (entrance == 'S')入口文字が「S」と異なる場合はパスベクトルに何もプッシュされず、空にして画面に何も表示されないことが指摘されています。後者のチェックpath.empty()または印刷をテストできますpath.size()

どちらにしても、ベクトルの代わりに文字列を使用した方がいいのではないでしょうか。配列のように文字列の内容にアクセスしたり、文字を検索したり、部分文字列を抽出したり、(ループなしで)文字列を簡単に出力したりできます。

すべてを文字列で行うと、複雑さを抑えて問題を特定しやすくなります。


3

オーバーロード演算子<<:

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

3

この回答はZorawarの回答に基づいていますが、コメントを残すことができませんでした。

代わりにcbeginおよびcendを使用して、自動(C ++ 11)/ typedefバージョンconstを作成できます。

for (auto i = path.cbegin(); i != path.cend(); ++i)
    std::cout << *i << ' ';

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] << ' ';

この回答では、既存の回答と比較して追加情報は提供されません。
Yashas

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;
}``
}

2
こんにちは!Stackoverflowへようこそ。コードスニペットに何をしているのか、それがどのように質問に答えるかについての説明を含めることができればすばらしいと思います。
Slabgorb


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;
    }

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<>ていますが、簡単にするためにここでは省略しています。


-1

独自の関数を書くことができます:

void printVec(vector<char> vec){
    for(int i = 0; i < vec.size(); i++){
        cout << vec[i] << " ";
    }
    cout << endl;
}

-1

ループなしのワンライナーが必要な場合:

私はこれを誰もが持っているとは信じられませんが、おそらくそれはよりCのようなアプローチによるものです。とにかく、ワンライナーでは、ループせずにこれを行うには完全に安全であると仮定していることstd::vector<char>、NULLで終了です。

std::vector<char> test { 'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!', '\0' };
std::cout << test.data() << std::endl;

しかしostream、安全のために、@ Zorawarが示唆するように、これをオペレーターでラップします。

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ループを使用すると、より高速になる可能性があります。


1
1. fprintf(stdout, "%s\n", &test[0]);と変わらないstd::cout << test.data()、両方のNULLで終了するベクターを必要とします。2. 「しかし、これをostream演算子でラップ <<する演算子を使用して、正しいオペランドを変更することは非常に悪い考えです。
HolyBlackCat

fprintf(stdout, "%s\n", &test[0]);コードで長い間使用してきましたが、問題が発生することはありません。面白い!そして、ベクトルのostream演算子を変更するのはそれほど良くないことには同意しますが、手動によるループイテレータの使用の両方が嫌いです。どういうわけかstd::vector<char>、標準ライブラリを印刷するような単純な操作では、標準ライブラリはこれらのものを隠す必要があります。しかし、C ++は絶えず開発されており、間もなく登場するかもしれません。
ワイキんぐ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.