Как распечатать содержимое вектора?
Я хочу, чтобы распечатать содержимое вектора в 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
будет не-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
класс-это объект, предназначенный для выполнения этой работы более сложные объекты, где это решение не будет идеальным.диапазон на основе цикла (C++11)
посмотреть Jefffrey это. В C++11 (и более поздних версиях) вы можете использовать новый диапазон на основе
for
петля, которая выглядит так:for (auto i: path) std::cout << i << ' ';
С
path
- это вектор элементов (явноstd::vector<char>
), объектi
имеет тип элемента вектора (т. е. явно имеет типchar
). Объектi
имеет значение это копия фактического элемента в , вы можете использовать ссылку: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
бросит, если вы попытаетесь получить доступ к элементу вне вектора и
гораздо проще сделать это со стандартным алгоритм копирования:
#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 принимает входной диапазон и callable объект, вызывая этот объект на каждом элементе диапазона. Ан входной диапазон определяется на два итераторы. А callable объект может быть функция, указатель на функцию, объект класса, который перегружает
() operator
или как в данном случае, лямбда-выражение. Параметр для этого выражения соответствует типу элементов из вектора.красота этой реализации-это сила, которую вы получаете от лямбда - выражений-вы можете использовать этот подход для гораздо большего, чем просто печать вектора.
проблема, вероятно, в предыдущем цикле:
(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; }