Como imprimir o conteúdo de um vetor?

Eu quero imprimir o conteúdo de um vetor em C ++, aqui está o que eu tenho:

#include  #include  #include  #include  #include  #include  #include  using namespace std; int main() { ifstream file("maze.txt"); if (file) { vector vec(istreambuf_iterator(file), (istreambuf_iterator())); vector 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 faço para imprimir o conteúdo do vetor na canvas?

Puramente para responder sua pergunta, você pode usar um iterador:

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

Se você quiser modificar o conteúdo do vetor no loop for, use o iterator vez de const_iterator .

Mas há muito mais que pode ser dito sobre isso. Se você quer apenas uma resposta que possa usar, então pode parar aqui; caso contrário, continue lendo.

auto (C ++ 11) / typedef

Isso não é outra solução, mas um suplemento para a solução iterator acima. Se você estiver usando o padrão C ++ 11 (ou posterior), poderá usar a palavra-chave auto para ajudar na legibilidade:

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

Mas o tipo de i será non-const (isto é, o compilador usará std::vector::iterator como o tipo de i ).

Neste caso, você pode simplesmente usar um typedef (não restrito ao C ++ 11, e muito útil para usar de qualquer maneira):

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

contador

Você pode, obviamente, usar um tipo inteiro para registrar sua posição no loop for :

 for(int i=0; i 

Se você for fazer isso, é melhor usar os tipos de membros do contêiner, se estiverem disponíveis e apropriados. std::vector tem um tipo de membro chamado size_type para este trabalho: é o tipo retornado pelo método de size .

 // Path typedef'd to std::vector for( Path::size_type i=0; i 

Por que não usar isso apenas na solução do iterator ? Para casos simples, você pode muito bem, mas o ponto é que a class iterator é um object projetado para fazer este trabalho para objects mais complicados onde esta solução não será ideal.

baseado em intervalo for loop (C ++ 11)

Veja a solução de Jefffrey . No C ++ 11 (e posterior) você pode usar o novo loop baseado for intervalo, que se parece com isto:

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

Como path é um vetor de itens (explicitamente std::vector ), o object i é do tipo do item do vetor (isto é, explicitamente, é do tipo char ). O object i tem um valor que é uma cópia do item real no object do path . Assim, todas as mudanças em i no loop não são preservadas no próprio path . Além disso, se você quiser impor o fato de não querer alterar o valor copiado de i no loop, você pode forçar o tipo de i a ser constar assim:

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

Se você gostaria de modificar os itens no path , você pode usar uma referência:

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

e mesmo que você não queira modificar o path , se a cópia dos objects for cara, você deve usar uma referência const ao invés de copiar por valor:

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

std :: copy

Veja a resposta de Joshua . Você pode usar o algoritmo STL std::copy para copiar o conteúdo do vetor no stream de saída. Esta é uma solução elegante se você estiver 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

Veja a solução de Max . Usar std::for_each é um exagero para este cenário simples, mas é uma solução muito útil se você quiser fazer mais do que apenas imprimir na canvas: usar std::for_each permite que você faça qualquer operação (sensata) no conteúdo do vetor.

sobrecarga ostream :: operator < <

Veja a resposta de Chris , isso é mais um complemento para as outras respostas, pois você ainda precisará implementar uma das soluções acima na sobrecarga. Em seu exemplo, ele usou um contador em um loop for . Por exemplo, é assim que você pode usar rapidamente a solução de Joshua :

 template  std::ostream& operator< < (std::ostream& out, const std::vector& v) { if ( !v.empty() ) { out < < '['; std::copy (v.begin(), v.end(), std::ostream_iterator(out, ", ")); out < < "\b\b]"; } return out; } 

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

conclusão

Qualquer uma das soluções apresentadas aqui funcionará. Cabe a você e ao código em qual deles é o "melhor". Qualquer coisa mais detalhada do que isso é provavelmente melhor deixar para outra pergunta onde os prós / contras podem ser devidamente avaliados; mas, como sempre, a preferência do usuário sempre desempenhará um papel: nenhuma das soluções apresentadas está errada, mas algumas parecerão mais interessantes para cada codificador individual.

termo aditivo

Esta é uma solução expandida de uma anterior que postei. Como esse post continuava chamando a atenção, decidi expandi-lo e me referir às outras excelentes soluções que foram postadas aqui. Meu post original tinha uma observação que mencionava que, se você pretendia modificar seu vetor dentro de um loop for , há dois methods fornecidos por std::vector para acessar os elementos: std::vector::operator[] que não faz limites verificação e std::vector::at que executa a verificação de limites. Em outras palavras, at arremesso, se você tentar acessar um elemento fora do vetor e o operator[] não o faria. Eu só adicionei este comentário, originalmente, para mencionar algo que pode ser útil saber se alguém já não o fez. E não vejo diferença agora. Daí esse adendo.

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

 #include  #include  // for copy #include  // for ostream_iterator #include  int main() { /* Set up vector to hold chars az */ std::vector 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(std::cout, " ")); return 0; } 

O ostream_iterator é o que é chamado de adaptador iterador . É modelado sobre o tipo para imprimir no stream (neste caso, char ). cout (também conhecido como saída do console) é o stream que queremos gravar, e o caractere de espaço ( " " ) é o que queremos imprimir entre cada elemento armazenado no vetor.

Esse algoritmo padrão é poderoso e muitos outros. O poder e a flexibilidade que a biblioteca padrão oferece são o que a tornam tão boa. Imagine só: você pode imprimir um vetor no console com apenas uma linha de código. Você não precisa lidar com casos especiais com o caractere separador. Você não precisa se preocupar com loops for-loops. A biblioteca padrão faz tudo para você.

Em C ++ 11, agora você pode usar um loop baseado em intervalo :

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

Acho que a melhor maneira de fazer isso é apenas sobrecarregar o operator< < adicionando essa function ao seu programa:

 #include  using std::vector; #include  using std::ostream; template ostream& operator< < (ostream& out, const vector& 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; } 

Então você pode usar o operador < < em qualquer vetor possível, assumindo que seus elementos também tenham ostream& operator< < definidos:

 vector s = {"first", "second", "third"}; vector b = {true, false, true, false, false}; vector 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} 

Como sobre a expressão for_each + lambda :

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

Naturalmente, uma solução baseada em intervalos é a solução mais elegante para essa tarefa concreta, mas essa também oferece muitas outras possibilidades.

Explicação

O algoritmo for_each usa um intervalo de input e um object que pode ser chamado, chamando esse object em todos os elementos do intervalo. Um intervalo de input é definido por dois iteradores . Um object que pode ser chamado pode ser uma function, um ponteiro para function, um object de uma class 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 essa abordagem para muito mais coisas do que apenas imprimir o vetor.

O problema provavelmente está no loop anterior: (x = 17; isalpha(firstsquare); x++) . Esse loop não será executado (se firstsquare não for alfa) ou será executado para sempre (se for alpha). A razão é que firstsquare não muda quando x é incrementado.

Basta copiar o contêiner para o console.

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

Deve saída:

 1 2 3 4 

No C ++ 11, um loop baseado em intervalo pode ser uma boa solução:

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

Saída:

 abc 

Eu vejo dois problemas. Como apontado em for (x = 17; isalpha(firstsquare); x++) há um loop infinito ou nunca executado, e também em if (entrance == 'S') se o caractere de input for diferente de ‘S’ então nada é empurrado para o vetor de caminho, deixando-o vazio e, portanto, imprimindo nada na canvas. Você pode testar o último verificando path.empty() ou imprimindo path.size() .

De qualquer forma, não seria melhor usar uma string em vez de um vetor? Você também pode acessar o conteúdo da string como uma matriz, buscar caracteres, extrair substrings e imprimir a string facilmente (sem loop).

Fazer tudo isso com strings pode ser o caminho para que seja escrito de maneira menos complicada e mais fácil de identificar o problema.

operador de sobrecarga < <:

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

Uso:

 vector  test {1,2,3}; wcout < < test; // or any output stream 

Esta resposta é baseada na resposta do Zorawar, mas eu não pude deixar um comentário lá.

Você pode fazer o auto (C ++ 11) / typedef versão const usando cbegin e cend em vez disso

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

Usando std::copy mas sem separador de trilha extra

Uma abordagem alternativa / modificada usando std::copy (como originalmente usado na resposta @JoshuaKravtiz ), mas sem include um separador à direita adicional após o último elemento:

 #include  #include  #include  #include  template  void print_contents(const std::vector& v, const char * const separator = " ") { if(!v.empty()) { std::copy(v.begin(), --v.end(), std::ostream_iterator(std::cout, separator)); std::cout < < v.back() << "\n"; } } // example usage int main() { std::vector 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; } 

Exemplo de uso aplicado ao contêiner de um tipo personalizado de 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 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; } 

Em C ++ 11“

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