Como imprimir o conteúdo de um vetor?

Quero Imprimir o conteúdo de um vector em C++, eis o que tenho:

#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;
    }
}
Como imprimo o conteúdo do vector ao ecrã?

Author: Vadim Kotov, 2012-05-25

13 answers

Só para responder à tua pergunta, podes usar um iterador:

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

Se quiser modificar o conteúdo do vector no for loop, então use iterator em vez de const_iterator.

Mas há muito mais que se pode dizer sobre isto. Se você só quer uma resposta que você pode usar, então você pode parar aqui; caso contrário, leia mais.

Auto (C++11) / typedef

Esta não é outra solução, mas um suplemento à solução acima iterator. Se estiver a usar a norma C++11 (ou mais tarde), então você pode usar a palavra-chave auto para ajudar a legibilidade:

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

Mas o tipo de i não será const (isto é, o compilador irá usar std::vector<char>::iterator como o tipo de i).

Neste caso, mais vale usar um typedef (não restrito a C++11, e muito útil para usar de qualquer forma):

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

Contador

É claro que pode usar um tipo inteiro para registar a sua posição no laço for:

for(int i=0; i<path.size(); ++i)
  std::cout << path[i] << ' ';

Se vai fazer isto, é melhor usar os tipos membros do container, se estiverem disponíveis e apropriados. std::vector tem um tipo de membro chamado size_type para este trabalho: é o tipo devolvido pelo método size.

// Path typedef'd to std::vector<char>
for( Path::size_type i=0; i<path.size(); ++i)
  std::cout << path[i] << ' ';
Porque não usar isto sobre a solução de iterator? Para casos simples você pode também, mas o ponto é que a classe iterator é um objeto projetado para fazer este trabalho para objetos mais complicados onde esta solução não vai ser ideal.

À Base de Range para o ciclo (C++11)

Vera solução de Jefffrey . No C++11 (e mais tarde), poderá usar o novo ciclo for baseado no intervalo, que se parece com o seguinte:

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

Uma vez que path é um vetor de itens (explicitamente std::vector<char>), o objeto i é do tipo do item do vetor (ou seja, explicitamente, é do tipo char). O objeto i tem um valor que é uma cópia do item real no objeto path. Assim, todas as mudanças em i no laço não são preservadas em path em si. Além disso, se você gostaria de impor o fato de que você não quer ser capaz de mudar o valor copiado de i no loop, você pode forçar o tipo de i a ser const char Assim:

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

Se quiser modificar os itens em path, pode usar uma referência:

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

E mesmo que não queira modificar path, se a cópia de objectos for cara, deve usar uma referência const em vez de copiar pelo valor:

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

Std::copy

Ver Joshua's resposta Pode usar o algoritmo STL std::copy para copiar o conteúdo do vector para a corrente de saída. Esta é uma solução elegante se você está confortável com ela (e, além disso, é muito útil, não apenas neste caso de imprimir o conteúdo de um vetor).

Std:: for_each

Ver a solução de Max . Usar std::for_each é um exagero para este cenário simples, mas é uma solução muito útil se quiser fazer mais do que apenas imprimir para o ecrã: usar std::for_each permite você deve fazer qualquer operação (sensível) sobre o conteúdo do vetor.

Sobrecarga em ostream: operador

Veja a resposta de Chris , isto é mais um complemento para as outras respostas, uma vez que você ainda precisará implementar uma das soluções acima na sobrecarga. Em seu exemplo, ele usou um contador em um laço for. Por exemplo, é assim que você pode usar rapidamente a solução de 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;
}

O uso de qualquer das outras soluções deve ser simples.

Conclusão

Qualquer das soluções aqui apresentadas funcionará. Depende de TI e do código em que é o "melhor". Qualquer coisa mais detalhada do que isso é provavelmente melhor deixado para outra pergunta onde os prós/contras podem ser adequadamente avaliados; mas como sempre a preferência do usuário sempre terá um papel: nenhuma das soluções apresentadas estão erradas, mas alguns vão olhar mais agradável para cada codificador individual.

Adenda

Esta é uma solução expandida de mais cedo eu postei. Desde que esse post continuou a chamar a atenção, eu decidi expandir sobre ele e se referir às outras soluções excelentes que foram postadas aqui. O meu post original tinha uma observação que mencionava que se você pretendia modificar o seu vector dentro de um laçofor, Então existem dois métodos fornecidos por std::vector para aceder aos elementos: std::vector::operator[] que não faz a verificação de limites, e std::vector::at que faz a verificação de limites. Em outras palavras, at irá lançar se você tentar acessar um elemento fora do vetor e operator[] não. eu só adicionei este comentário, originalmente, para mencionar algo que poderia ser útil saber se alguém já não o fez. e eu não vejo nenhuma diferença agora. Daí esta adenda.
 287
Author: Zorawar, 2017-05-23 12:18:24

Uma maneira muito mais fácil de fazer isto é com o algoritmo de cópia padrão :

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

O ostream_iterador é o que se chama um adaptador iterador . É templatizado sobre o tipo a imprimir para o fluxo (neste caso, char). cout (também conhecido como saída de consola) é o fluxo para o qual queremos escrever, e o carácter do espaço (" ") é o que queremos imprimir entre cada elemento armazenado no vector.

Este algoritmo padrão é poderoso, assim como muitos outros. O poder e flexibilidade que a biblioteca padrão lhe dá são o que a torna tão grande. Basta imaginar: você pode imprimir um vetor para a consola com apenas uma linha de código. Não tens de lidar com casos especiais com o Carácter separador. Não precisas de te preocupar com isso. A biblioteca normal faz tudo por ti.

 184
Author: Joshua Kravitz, 2016-06-06 12:57:26

Em C++11 pode agora usar um intervalo para o loop:

for (auto const& c : path)
    std::cout << c << ' ';
 62
Author: Shoe, 2016-02-01 16:41:04

Acho que a melhor maneira de fazer isto é sobrecarregar {[3] } adicionando esta função ao seu programa:

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

Depois pode usar o operador << em qualquer vector possível, assumindo que os seus elementos também têm ostream& operator<< definido:

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;

Saídas:

{first, second, third}
{1, 0, 1, 0, 0}
{1, 2, 3, 4}
 32
Author: Chris Redford, 2018-04-02 18:35:06
Que tal ... for_each + expressão lambda:
#include <vector>
#include <algorithm>
...
std::vector<char> vec;
...
std::for_each(
              vec.cbegin(),
              vec.cend(),
              [] (const char c) {std::cout << c << " ";} 
              );
...

Claro, uma gama debaseada em é a solução mais elegante para esta tarefa concreta, mas esta também dá muitas outras possibilidades.

Anotações

O algoritmo for_each toma um intervalo de entrada e um objecto chamável , chamando este objecto para cada elemento do intervalo. Um intervalo de entrada é definido por dois iteradores . Umobjecto chamável pode ser uma função, um ponteiro para função, um objeto de uma classe que sobrecarrega () operator ou como neste caso, uma expressão lambda. O parâmetro para esta expressão corresponde ao tipo dos elementos do vetor.

A beleza desta implementação é o poder que você obtém das expressões lambda-você pode usar esta abordagem para muito mais coisas do que apenas imprimir o vetor.

 13
Author: Max Chetrusca, 2014-10-14 14:48:38

O problema está provavelmente no loop anterior: (x = 17; isalpha(firstsquare); x++). Este ciclo não irá correr de todo (se firstsquare não for alfa) ou irá correr para sempre (se for Alfa). A razão é que firstsquare não muda porque {[3] } é aumentado.

 7
Author: MSalters, 2012-05-25 07:19:07
Copia o contentor para a consola.
std::vector<int> v{1,2,3,4};
std::copy(v.begin(),v.end(),std::ostream_iterator<int>(std::cout, " " ));

Deve sair:

1 2 3 4
 5
Author: g24l, 2018-05-06 12:20:22

Em C++11, uma gama de loop pode ser uma boa solução:

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

Resultado:

a b c 
 4
Author: stupidgoddamnjerk, 2018-08-11 15:11:35
Vejo dois problemas. Como indicado em {[[0]}, existe um laço infinito ou nunca executado, e também em if (entrance == 'S') Se o carácter de entrada é diferente de' S', então nada é empurrado para o vector path, tornando-o vazio e, portanto, imprimindo nada na tela. Você pode testar a última verificação para path.empty() ou imprimir path.size(). De qualquer forma, não seria melhor usar uma corda em vez de um vector? Você pode acessar o conteúdo do texto como um array também, procurar caracteres, extrair substratos e imprimir a string facilmente (sem um laço). Fazer tudo com cordas pode ser a forma de escrever de uma forma menos complicada e mais fácil de detectar o problema.
 2
Author: miguelbernadi, 2012-05-25 07:32:50

Operador de sobrecarga

template<typename OutStream, typename T>
OutStream& operator<< (OutStream& out, const vector<T>& v)
{
    for (auto const& tmp : v)
        out << tmp << " ";
    out << endl;
    return out;
}

Utilização:

vector <int> test {1,2,3};
wcout << test; // or any output stream
 2
Author: ivanmara, 2016-08-12 00:28:24
Esta resposta baseia-se na resposta de Zorawar, mas não podia deixar um comentário.

Você poderá fazer o auto (C++11)/typedef version const, usando o cbegin e o cend em alternativa

for (auto i = path.cbegin(); i != path.cend(); ++i)
    std::cout << *i << ' ';
 1
Author: SketchyManDan, 2017-02-07 16:28:58

Usando std::copy mas sem separador de saída extra

Uma abordagem alternativa / modificada utilizando std::copy (Como foi usado originalmente em @JoshuaKravtiz answer ), mas sem incluir um separador adicional após o último elemento:

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

Uso de exemplo aplicado ao Contentor de um tipo de POD personalizado:

// 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;
}
 1
Author: dfri, 2017-07-30 13:34:54

Em 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] << ' ';
 0
Author: harrypotter0, 2017-11-24 14:38:28