Cómo imprimir el contenido de un vector?


Quiero imprimir el contenido de un vector en C++, esto es lo que tengo:

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

¿Cómo puedo imprimir el contenido del vector en la pantalla?

Author: Vadim Kotov, 2012-05-25

13 answers

Simplemente para responder a tu pregunta, puedes usar un iterador:{[49]]}

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

Si desea modificar el contenido del vector en el bucle for, utilice iterator en lugar de const_iterator.

Pero hay mucho más que se puede decir sobre esto. Si solo quieres una respuesta que puedas usar, entonces puedes parar aquí; de lo contrario, sigue leyendo.

Auto (C++11)/typedef

Esta no es otra solución, sino un suplemento a la solución anterior iterator. Si está utilizando el estándar C++11 (o más tarde), entonces puedes usar la palabra clave auto para ayudar a la legibilidad:

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

Pero el tipo de i no será const (es decir, el compilador utilizará std::vector<char>::iterator como el tipo de i).

En este caso, también podría usar un typedef (no restringido a C++11, y muy útil para usar de todos modos):

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

Contador

Por supuesto, puede usar un tipo entero para registrar su posición en el bucle for:

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

Si vas a hacer esto, es mejor usar los tipos de miembros del contenedor, si están disponibles y son apropiados. std::vector tiene un tipo miembro llamado size_type para este trabajo: es el tipo devuelto por el método size.

// Path typedef'd to std::vector<char>
for( Path::size_type i=0; i<path.size(); ++i)
  std::cout << path[i] << ' ';

¿Por qué no usar esto sobre la solución iterator? Para casos simples también podría, pero el punto es que la clase iterator es un objeto diseñado para hacer este trabajo para objetos más complicados donde esta solución no va a ser ideal.

Bucle for basado en rango (C++11)

Ver La solución de Jefffrey. En C++11 (y posteriores) puedes usar el nuevo bucle for basado en rangos, que se ve así:

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

Ya que path es un vector de elementos (explícitamente std::vector<char>), el objeto i es de tipo del elemento del vector (es decir, explícitamente, es de tipo char). El objeto i tiene un valor que es una copia del elemento real en el objeto path. Por lo tanto, todos los cambios a i en el bucle no se conservan en path. Además, si te gustaría hacer valer el hecho de que usted no desea ser capaz de cambiar el copiado valor de i en el bucle, se puede forzar el tipo de i a const char como esto:

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

Si desea modificar los elementos en path, puede usar una referencia:

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

E incluso si no desea modificar path, si la copia de objetos es costosa, debe usar una referencia const en lugar de copiar por valor:

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

Std:: copy

Ver Joshua answer . Puede usar el algoritmo STL std::copy para copiar el contenido vectorial en el flujo de salida. Esta es una solución elegante si se siente cómodo con ella (y además, es muy útil, no solo en este caso de imprimir el contenido de un vector).

Std::for_each

Ver La solución de Max. Usar std::for_each es excesivo para este escenario simple, pero es una solución muy útil si desea hacer más que solo imprimir en pantalla: usar std::for_each permite debe hacer cualquier operación (sensible) sobre el contenido del vector.

Sobrecarga ostream:: operador

Ver La respuesta de Chris, esto es más un complemento a las otras respuestas ya que todavía tendrá que implementar una de las soluciones anteriores en la sobrecarga. En su ejemplo usó un contador en un bucle for. Por ejemplo, así es como puedes usar rápidamente La solución de Josué :

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

El uso de cualquiera de las otras soluciones debe ser sencillo.

Conclusión

Cualquiera de las soluciones presentadas aquí funcionará. Depende de ti y del código en el que uno es el "mejor". Cualquier cosa más detallada que esto es probablemente mejor dejar para otra pregunta donde los pros / contras se pueden evaluar correctamente; pero como siempre la preferencia del usuario siempre jugará un papel: ninguna de las soluciones presentadas están equivocadas, pero algunas se verán mejor para cada codificador individual.

Adición

Esta es una solución expandida de un la anterior que publiqué. Dado que ese post seguía recibiendo atención, decidí ampliarlo y referirme a las otras excelentes soluciones que se publicaron aquí. Mi post original tenía un comentario que mencionaba que si estaba intentando modificar su vector dentro de un bucle for, entonces hay dos métodos proporcionados por std::vector para acceder a los elementos: std::vector::operator[] que no realiza la comprobación de límites, y std::vector::at que realiza la comprobación de límites. En otras palabras, at lanzará si intenta acceder a un elemento fuera del vector y operator[] no lo haría. Solo agregué este comentario, originalmente, para mencionar algo que podría ser útil saber si alguien ya no lo hizo. Y no veo ninguna diferencia ahora. De ahí la presente adición.

 287
Author: Zorawar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:18:24

Una forma mucho más fácil de hacer esto es con el algoritmo de copia estándar :

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

El ostream_iterator es lo que se llama un adaptador iterador . Se templatiza sobre el tipo para imprimir en la secuencia (en este caso, char). cout (también conocido como salida de consola) es la secuencia en la que queremos escribir, y el carácter de espacio (" ") es lo que queremos imprimir entre cada elemento almacenado en el vector.

Este algoritmo estándar es poderoso y también lo son muchos otros. Energía y la flexibilidad que la biblioteca estándar le da es lo que la hace tan grande. Imagínese: puede imprimir un vector en la consola con solo una línea de código. No tiene que tratar con casos especiales con el carácter separador. No tienes que preocuparte por los bucles. La biblioteca estándar lo hace todo por usted.

 184
Author: Joshua Kravitz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-06 12:57:26

En C++11 ahora puede usar un bucle for basado en rango :

for (auto const& c : path)
    std::cout << c << ' ';
 62
Author: Shoe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-02-01 16:41:04

Creo que la mejor manera de hacer esto es simplemente sobrecargar operator<< agregando esta función a su 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;
}

Entonces puede usar el operador << en cualquier vector posible, asumiendo que sus elementos también tienen 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;

Salidas:

{first, second, third}
{1, 0, 1, 0, 0}
{1, 2, 3, 4}
 32
Author: Chris Redford,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-02 18:35:06

¿Qué tal for_each + expresión lambda :

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

Por supuesto, un rango para es la solución más elegante para esta tarea concreta, pero esto da muchas más posibilidades.

Explicación

El algoritmo for_each toma un rango de entrada y un objeto llamable , llamando a este objeto en cada elemento del rango. Un rango de entrada está definido por dos iteradores . Un objeto invocable puede ser un function, un puntero a function, un objeto de una clase que sobrecarga () operator o como en este caso, una expresión lambda. El parámetro para esta expresión coincide con el tipo de los elementos de vector.

La belleza de esta implementación es el poder que obtiene de las expresiones lambda: puede usar este enfoque para muchas más cosas que solo imprimir el vector.

 13
Author: Max Chetrusca,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-10-14 14:48:38

El problema está probablemente en el bucle anterior: (x = 17; isalpha(firstsquare); x++). Este bucle no se ejecutará en absoluto (si firstsquare no es alfa) o se ejecutará para siempre (si es alfa). La razón es que firstsquare no cambia a medida que x se incrementa.

 7
Author: MSalters,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-05-25 07:19:07

Simplemente copie el contenedor a la consola.

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

Debería generar:

1 2 3 4
 5
Author: g24l,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-05-06 12:20:22

En C++11, un bucle for basado en rango podría ser una buena solución:

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

Salida:

a b c 
 4
Author: stupidgoddamnjerk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-11 15:11:35

, veo dos problemas. Como se señala en for (x = 17; isalpha(firstsquare); x++) hay un bucle infinito o nunca ejecutado, y también en if (entrance == 'S') si el carácter de entrada es diferente de 'S', entonces nada se empuja al vector de ruta, lo que lo vacía y por lo tanto no imprime nada en la pantalla. Puede probar este último comprobando path.empty() o imprimiendo path.size().

De cualquier manera, ¿no sería mejor usar una cadena en lugar de un vector? También puede acceder al contenido de la cadena como una matriz, buscar caracteres, extraer subcadenas e imprimir la cadena fácilmente (sin un bucle).

Hacerlo todo con cadenas podría ser la manera de tenerlo escrito de una manera menos complicada y más fácil de detectar el problema.

 2
Author: miguelbernadi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
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;
}

Uso:

vector <int> test {1,2,3};
wcout << test; // or any output stream
 2
Author: ivanmara,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-12 00:28:24

Esta respuesta se basa en la respuesta de Zorawar, pero no podía dejar un comentario allí.

Puede hacer que la versión auto (C++11)/typedef const usando cbegin y cend en su lugar

for (auto i = path.cbegin(); i != path.cend(); ++i)
    std::cout << *i << ' ';
 1
Author: SketchyManDan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-07 16:28:58

Usando std::copy pero sin separador final adicional

Un enfoque alternativo / modificado utilizando std::copy (como se usó originalmente en @ JoshuaKravtiz answer ) pero sin incluir un separador final adicional después del ú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;
}

Ejemplo de uso aplicado al contenedor de un 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,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-30 13:34:54

En 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,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-24 14:38:28