Как распечатать содержимое вектора?

Я хочу распечатать содержимое вектора на 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;
    }
}

Как распечатать содержимое вектора на экране?

13 ответов


чисто, чтобы ответить на ваш вопрос, вы можете использовать итератор:

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

если вы хотите изменить содержимое вектора в цикле for, используйте iterator, а не const_iterator.

но об этом можно сказать гораздо больше. Если вам просто нужен ответ, который вы можете использовать, вы можете остановиться здесь; в противном случае читайте дальше.

auto (C++11)/typedef

это не другое решение, а дополнение к вышесказанному iterator решение. Если вы используете стандарт C++11 (или позже), то вы можете использовать auto ключевое слово, чтобы помочь удобочитаемости:

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

но типа i будет non-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 << ' ';

счетчик

вы можете, конечно, использовать тип integer в запишите свою позицию в 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 class-это объект, предназначенный для выполнения этой работы для более сложные объекты, где это решение не будет идеальным.

диапазон на основе цикла (C++11)

посмотреть Jefffrey это. В C++11 (и более поздних версиях) вы можете использовать новый диапазон на основе for цикл, который выглядит так:

for (auto i: path)
  std::cout << i << ' ';

С path является вектором элементов (явно std::vector<char>), объект i имеет тип элемента вектора (т. е. явно имеет тип char). Объект i имеет значение это копия фактического элемента в . Кроме того, если вы хотите применить тот факт, что вы не хотите иметь возможность изменять скопированное значение i в цикле вы можете принудительно ввести тип i на const char такой:

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

если вы хотите изменить элементы!--25-->, вы можете использовать ссылку:

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

посмотреть Макс. Используя std::for_each является излишним для этого простого сценария, но это очень полезное решение, если вы хотите сделать больше, чем просто печать на экран: использование std::for_each позволяет сделать любой (разумная) операция над векторным содержимым.

перегрузка ostream:: operator

посмотреть ответ Криса, это больше дополнение к другим ответам так как вам все равно нужно будет реализовать одно из вышеперечисленных решений при перегрузке. В своем примере он использовал счетчик в 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;
}

использование любого из других решений должно быть простым.

вывод

любым из представленных здесь решений будет работать. Это зависит от вас и кода, на котором он является "лучшим". Что-нибудь более подробное, чем это, вероятно, лучше оставить для другого вопроса, где плюсы/минусы могут быть правильно оценены; но, как всегда, предпочтение пользователя всегда будет играть свою роль: ни одно из представленных решений не является неправильным, но некоторые будут выглядеть лучше для каждого отдельного кодера.

дополнительное соглашение

это расширенное решение более раннего, которое я опубликовал. Поскольку этот пост продолжал привлекать внимание, я решил расширить его и сослаться на другие отличные решения, которые были размещены здесь. Мой оригинальный пост было замечание, которое упоминало, что если вы были намереваясь изменить свой вектор внутри for цикл, то есть два метода, предоставляемые std::vector для доступа к элементам:std::vector::operator[], который не делает проверку границ, и std::vector::at который выполняет проверку границ. Другими словами,at будет бросать, если вы попытаетесь получить доступ к элементу вне вектора и operator[] не стал бы. Я только добавил этот комментарий, первоначально, ради упоминания чего-то, что может быть полезно чтобы знать, если кто-то уже не знал. И теперь я не вижу разницы. Отсюда и это добавление.


гораздо проще сделать это со стандартным алгоритм копирования:

#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 console output) - это поток, в который мы хотим писать, и символ пробела (" ") - это то, что мы хотим напечатать между каждым элементом, хранящимся в векторе.

этот стандартный алгоритм могущественны и многие другие. Сила и гибкость стандартная библиотека дает вам то, что делает его таким большим. Только представьте: вы можете напечатать вектор на консоль только с помощью один строка кода. Вам не нужно иметь дело с особыми случаями с символом разделителя. Вам не нужно беспокоиться о for-loops. Стандартная библиотека делает все за вас.


В C++11 Теперь вы можете использовать диапазон на основе цикла:

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 << " ";} 
              );
...

конечно, a на основе диапазона для это самое простое решение для этой конкретной задачи, но это дает много других возможностей.

объяснение

на принимает входной диапазон и a callable объект, вызывая этот объект на каждом элементе диапазона. Ан входной диапазон определяется два итераторы. А callable объект может быть функцией, указателем на функцию, объектом класса, который перегружает () operator или как в данном случае, лямбда-выражение. Параметр для этого выражения соответствует типу элементов из vector.

красота этой реализации-это сила, которую вы получаете от лямбда-выражений - вы можете использовать этот подход для гораздо большего, чем просто печать вектора.


проблема, вероятно, в предыдущем цикле:(x = 17; isalpha(firstsquare); x++). Этот цикл не будет работать вообще (если firstsquare не-альфа) или будет работать вечно (если это альфа). Причина в том, что firstsquare не изменяется как x увеличивается.


просто скопируйте контейнер в консоль.

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 на основе диапазона может быть хорошим решением:

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

выход:

a b c 

Я вижу две проблемы. Как указано в for (x = 17; isalpha(firstsquare); x++) тут либо бесконечный цикл, либо не выполняется вообще, а также в if (entrance == 'S') если символ входа отличается от "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

этот ответ базируется на ответ от Зоравар, но я не могу оставить там комментарий.

вы можете сделать auto (C++11)/typedef версии const, используя cbegin и cend вместо

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

используя 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++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] << ' ';