c++ - push_back - vector insert




如何打印出矢量的內容? (9)

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

應用於自定義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;
}

我想用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<int> v{1,2,3,4};
std::copy(v.begin(),v.end(),std::ostream_iterator<int>(std::cout, " " ));

應該輸出:

1 2 3 4

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

在C ++ 11中,基於範圍的for循環可能是一個很好的解決方案:

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

輸出:a b c


如何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表達式 。 該表達式的參數與來自向量的元素的類型相匹配。

這種實現的美妙之處在於你從lambda表達式中獲得的力量 - 你可以使用這種方法獲得比印刷矢量更多的東西。


我看到兩個問題。 正如在for (x = 17; isalpha(firstsquare); x++)指出的那樣,如果入口字符不是'S', if (entrance == 'S')就有一個無限循環或永遠不會執行, if (entrance == 'S') 'S'那麼沒有任何東西被推送到路徑向量中,使其變為空白,從而在屏幕上不進行任何打印。 您可以測試後者檢查path.empty()或打印path.size()

無論哪種方式,使用字符串代替矢量不是更好嗎? 您也可以像數組一樣訪問字符串內容,查找字符,提取子字符串並輕鬆打印字符串(不帶循環)。

用字符串做這一切可能是以不太複雜的方式寫出來並更容易發現問題的方法。


更簡單的方法是使用標準複製算法

#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 (aka控制台輸出)是我們要寫入的流,而空格字符( " " )是我們想要在存儲在向量中的每個元素之間打印的內容。

這個標準算法功能強大,其他許多算法也是如此。 標準庫為您提供的強大功能和靈活性讓它變得如此優秀。 試想一下:只需一行代碼就可以將矢量打印到控制台。 您不必使用分隔符處理特殊情況。 你不需要擔心for循環。 標準庫為你做這一切。


純粹為了回答你的問題,你可以使用迭代器:

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類是一個對象,用於處理更複雜的對象,而這個解決方案並不理想。

基於範圍的循環(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 << ' ';

性病::複製

見約書亞的回答 。 您可以使用STL算法std::copy將矢量內容複製到輸出流中。 如果你對它感到滿意,這是一個優雅的解決方案(此外,它非常有用,而不僅僅是在打印矢量內容的情況下)。

的std :: for_each的

參見Max的解決方案 。 使用std::for_each對於這個簡單的場景來說是矯枉過正的,但是如果你不僅僅想打印到屏幕上,它是一個非常有用的解決方案:使用std::for_each允許你對矢量內容進行任何 (明智的)操作。

超載ostream :: operator <<

請參閱克里斯的回答 ,這是對其他答案的補充,因為您仍然需要在重載中實現上述解決方案之一。 在他的例子中,他在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;
}

任何其他解決方案的使用應該很簡單。

結論

這裡介紹的任何解決方案都可以工作。 這取決於你和哪一個是最好的代碼。 比這更詳細的任何事情可能是最好留給另一個問題的優點/缺點可以適當評估; 但始終用戶偏好總是起作用:所提供的解決方案都不是錯誤的,但有些對每個單獨的編碼器都會更好看。

附錄

這是我發布的較早版本的擴展解決方案。 既然這篇文章一直受到關注,我決定擴展它,並參考其他在此發布的優秀解決方案。 我原來的帖子有一句話提到,如果你打算在for循環中修改你的vector for那麼std::vector提供兩個訪問元素的方法: std::vector::operator[] ,它不會做邊界檢查,和std::vector::at哪個確實執行邊界檢查。 換句話說,如果你嘗試訪問矢量以外的元素並且operator[]不會,將會拋出。 最初,我只是為了提及某些事情而添加此評論,以便知道是否有人已經做不到。 我現在看到沒有區別。 因此這個附錄。


這個答案是基於Zorawar的回答,但我不能在那裡留言。

你可以使用cbegin和cend來改變auto(C ++ 11)/ typedef的版本

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




out