Archive for the ‘C++’ Category

Menú en la terminal de GNU/Linux con C++ y códigos de escape

enero 4, 2013

El hacer un programa en modo texto para GNU/Linux en C++ que muestre un menú con una barra que se controle con las flechas del teclado implica más trabajo del que se requiere para lograr lo mismo si nuestro programa fuera a ejecutarse en un sistema operativo basado en DOS (ya sea MS-DOS, Windows, etc.)

A continuación muestro una posible solución de como lograrlo sin utilizar ncurses, únicamente códigos de escape, esto tiene la pequeña desventaja de que no funciona para cualquier terminal, pero para xterm y algunas otras no debe haber problema

Crearemos una fución que espere a que el usuario pulse una tecla y regrese el valor correspondiente a esa tecla, la función debe tomar en cuenta las teclas que al ser pulsadas regresan tres valores, siendo el primer valor el que corresponde a la tecla ESC (que es el 27)

int lee_caracter()
{
 struct termios config_ant;
 struct termios config_nueva;
 int caracter;

 tcgetattr(STDIN_FILENO, &config_ant);
 config_nueva = config_ant;                /* Guarda los valores actuales de configuración de la terminal */
 config_nueva.c_lflag &= ~(ICANON | ECHO); /* resetea las banderas canonical y echo para que no se muestre en pantalla lo que se teclea*/
 tcsetattr(STDIN_FILENO, TCSANOW, &config_nueva); /* Establece los nuevos valores para la terminal */
 caracter = getchar();

 // si se pulsa una tecla que empieza con un código de escape
 if (caracter==27)
    {
     caracter=getchar();
     if (caracter==91)
         caracter=getchar(); //caracter ahora tiene el valor de la tecla pulsada
    }

 tcsetattr(STDIN_FILENO, TCSANOW, &config_ant); /* Vuelve a poner los valores originales de configuración de la terminal */

 return caracter;
}

Los atributos y colores que podemos manejar son los siguientes:

#define RESET        0
#define BRIGHT       1
#define DIM          2
#define UNDERLINE    3
#define BLINK        4
#define REVERSE      7
#define HIDDEN       8
#define BLACK        0
#define RED          1
#define GREEN        2
#define YELLOW       3
#define BLUE         4
#define MAGENTA      5
#define CYAN         6
#define WHITE        7

Necesitamos también una función que nos permita establecer el atributo, color de la fuente y color de fondo que vamos a utilizar antes de escribir un texto

void ColorTexto(int atributo, int texto, int fondo)
{
 std::string color = "\033["+toString(atributo)+";"+toString(texto+30)+";"+toString(fondo+40)+"m";
 cout<<color;
}

Este programa utiliza las dos funciones descritas anteriores para mostrar un menú vertical, se asume una terminal de 80 columnas

/*
Debido a que este programa usa el archivo de cabecera termios.h,
sólo funciona en sistemas operativos que cumplan con el estándar POSIX
Es decir, cualquier distribución de GNU/Linux o cualquier Unix.
*/

#include <iostream>
#include <sstream>    /* Para poder usar istringstream */
#include <string>
#include <termios.h>  /* Para poder usar las estructuras termios */
#include <stdio.h>    /* Para poder usar getchar() */
#include <iomanip>    /* Para poder usar setw */

#define RESET        0
#define BRIGHT       1
#define DIM          2
#define UNDERLINE    3
#define BLINK        4
#define REVERSE      7
#define HIDDEN       8

#define BLACK        0
#define RED          1
#define GREEN        2
#define YELLOW       3
#define BLUE         4
#define MAGENTA      5
#define CYAN         6
#define WHITE        7

const std::string default_console = "\033[0m";

using std::cout;
using std::endl;
using std::setw;

template <typename T>
static std::string toString (T numero)
{
 std::ostringstream ss;
 ss << numero;
 return ss.str();
}

void ColorTexto(int atributo, int texto, int fondo);
int lee_caracter();
void ImprimeMenu(std::string menu[], int tamanio, int op);

int main()
{
 std::string str_menu[4] = {"1. Registrar", "2. Consultar", "3. Modificar", "4. Salir    "};
 int tecla, opcion=0, seleccion=1;

do
 {
  ImprimeMenu(str_menu,4,seleccion);
  tecla = lee_caracter();

  switch (tecla)
         {
          case 10:
                  // Enter
                  opcion = seleccion;
                  break;
          case 65:
                  // Flecha arriba
                  seleccion = (seleccion==1 ? 4 : seleccion-1);
                  opcion = 0;
                  break;
          case 66:
                  // Flecha abajo
                  seleccion = (seleccion==4 ? 1 : seleccion+1);
                  opcion = 0;
                  break;
          default:
                  opcion = tecla-48;
                  if (opcion>=1 && opcion<=4)
                     {
                      seleccion = opcion;
                      ImprimeMenu(str_menu,4,seleccion);
                     }
         }
  if (opcion>=1 && opcion<=4)
     {
      cout<<"Opcion "<<opcion<<endl;
      lee_caracter();
     }
  }
 while (opcion!=4);

 return 0;
}

void ColorTexto(int atributo, int texto, int fondo)
{
 std::string color = "\033["+toString(atributo)+";"+toString(texto+30)+";"+toString(fondo+40)+"m";
 cout<<color;
}

int lee_caracter()
{
 struct termios config_ant;
 struct termios config_nueva;
 int caracter;

 tcgetattr(STDIN_FILENO, &config_ant);
 config_nueva = config_ant;                /* Guarda los valores actuales de configuración de la terminal */
 config_nueva.c_lflag &= ~(ICANON | ECHO); /* resetea las banderas canonical y echo para que no se muestre en pantalla lo que se teclea*/
 tcsetattr(STDIN_FILENO, TCSANOW, &config_nueva); /* Establece los nuevos valores para la terminal */
 caracter = getchar();

 // si se pulsa una tecla que empieza con un código de escape
 if (caracter==27)
    {
     caracter=getchar();
     if (caracter==91)
         caracter=getchar(); //caracter ahora tiene el valor de la tecla pulsada
    }

 tcsetattr(STDIN_FILENO, TCSANOW, &config_ant); /* Vuelve a poner los valores originales de configuración de la terminal */

 return caracter;
}

void ImprimeMenu(std::string menu[], int tamanio, int op)
{
 int x=0, pos;
 unsigned int longitud=0;

 // Obtiene la longitud de la opción del menú con más caracteres
 for (x=0; x<tamanio; ++x)
     {
      if (menu[x].length() > longitud)
          longitud = menu[x].length();
     }
 pos = (80 - longitud) / 2;

 // Limpia la pantalla
 cout << "\033[2J\033[1;1H";

 for (x=0; x<tamanio; ++x)
     {
      // Deja el número de espacios adecuado para que el menú quede centrado (se asume una pantalla de 80 caracteres)
      cout<<default_console;
      cout<<setw(pos)<<" ";

      if (x+1==op)
          ColorTexto(BRIGHT,YELLOW,MAGENTA);
      else
          ColorTexto(BRIGHT,WHITE,BLUE);
      cout<<menu[x]<<endl;
     }
 cout<<default_console<<endl;
}

menu

Ahora la versión para mostrar el menú en forma horizontal

/*
 Debido a que este programa usa el archivo de cabecera termios.h,
 sólo funciona en sistemas operativos que cumplan con el estándar POSIX
 Es decir, cualquier distribución de GNU/Linux o cualquier Unix.
*/

#include <iostream>
#include <sstream>    /* Para poder usar istringstream */
#include <string>
#include <termios.h>  /* Para poder usar las estructuras termios */
#include <stdio.h>    /* Para poder usar getchar() */
#include <iomanip>    /* Para poder usar setw */

#define RESET        0
#define BRIGHT       1
#define DIM          2
#define UNDERLINE    3
#define BLINK        4
#define REVERSE      7
#define HIDDEN       8

#define BLACK        0
#define RED          1
#define GREEN        2
#define YELLOW       3
#define BLUE         4
#define MAGENTA      5
#define CYAN         6
#define WHITE        7

const std::string default_console = "\033[0m";

using std::cout;
using std::endl;
using std::setw;

template <typename T>
static std::string toString (T numero)
{
 std::ostringstream ss;
 ss << numero;
 return ss.str();
}

void ColorTexto(int atributo, int texto, int fondo);
int lee_caracter();
void ImprimeMenu(std::string menu[], int tamanio, int op);

int main()
{
 std::string str_menu[4] = {"1. Registrar", "2. Consultar", "3. Modificar", "4. Salir"};
 int tecla, opcion=0, seleccion=1;

 do
   {
    ImprimeMenu(str_menu,4,seleccion);
    tecla = lee_caracter();

    switch (tecla)
           {
            case 10:
                    // Enter
                    opcion = seleccion;
                    break;
            case 67:
                    // Flecha derecha
                    seleccion = (seleccion==4 ? 1 : seleccion+1);
                    opcion = 0;
                    break;
            case 68:
                    // Flecha izquierda
                    seleccion = (seleccion==1 ? 4 : seleccion-1);
                    opcion = 0;
                    break;
            default:
                    opcion = tecla-48;
                    if (opcion>=1 && opcion<=4)
                       {
                        seleccion = opcion;
                        ImprimeMenu(str_menu,4,seleccion);
                       }
           }
    if (opcion>=1 && opcion<=4)
       {
        cout<<"Opcion "<<opcion<<endl;
        lee_caracter();
       }
   }
 while (opcion!=4);

 return 0;
}

void ColorTexto(int atributo, int texto, int fondo)
{
 std::string color = "\033["+toString(atributo)+";"+toString(texto+30)+";"+toString(fondo+40)+"m";
 cout<<color;
}

int lee_caracter()
{
 struct termios config_ant;
 struct termios config_nueva;
 int caracter;

 tcgetattr(STDIN_FILENO, &config_ant);
 config_nueva = config_ant;                /* Guarda los valores actuales de configuración de la terminal */
 config_nueva.c_lflag &= ~(ICANON | ECHO); /* resetea las banderas canonical y echo para que no se muestre en pantalla lo que se teclea*/
 tcsetattr(STDIN_FILENO, TCSANOW, &config_nueva); /* Establece los nuevos valores para la terminal */
 caracter = getchar();

 // si se pulsa una tecla que empieza con un código de escape
 if (caracter==27)
    {
     caracter=getchar();
     if (caracter==91)
         caracter=getchar(); //caracter ahora tiene el valor de la tecla pulsada
    }

 tcsetattr(STDIN_FILENO, TCSANOW, &config_ant); /* Vuelve a poner los valores originales de configuración de la terminal */

 return caracter;
}

void ImprimeMenu(std::string menu[], int tamanio, int op)
{
 int x=0, pos;
 unsigned int longitud=0;

 // Obtiene la longitud total del menú dejando dos espacios entre cada opción
 for (x=0; x<tamanio; ++x)
     {
      longitud += menu[x].length();
      if (x!=tamanio-1)
          longitud +=2;
     }

 pos = (80 - longitud) / 2;

 // Limpia la pantalla
 cout << "\033[2J\033[1;1H";

 // Deja el número de espacios adecuado para que el menú quede centrado (se asume una pantalla de 80 caracteres)
 cout<<setw(pos)<<" ";
 for (x=0; x<tamanio; ++x)
     {
      if (x+1==op)
          ColorTexto(BRIGHT,YELLOW,MAGENTA);
      else
          ColorTexto(BRIGHT,WHITE,BLUE);
      cout<<menu[x];
      if (x!=tamanio-1)
        {
         ColorTexto(BRIGHT,WHITE,BLUE);
         cout<<"  ";
        }
     }
 cout<<default_console<<endl;
}

menuh

Anuncios

Gráfica de barras horizontales en la terminal con C++

diciembre 14, 2011

Ya en un post anterior había escrito sobre la STL de C++; el código siguiente simula una gráfica de barras horizontales en modo texto y aprovecho para ejemplificar el uso de algunas funciones y algoritmos de la STL.
El programa consiste en pedirle al usuario que capture números positivos y los va almacenando en un vector, para terminar la captura el usuario debe introducir un número negativo. Una vez terminada la captura, se copian los valores almacenados en el vector a otro vector y después se ordenan para que en el vector original los números queden en el mismo orden en que el usuario los fue capturando. Esta parte de copiar los valores de un vector a otro y ordenar los valores en el segundo vector no es necesaria para el funcionamiento del programa, sólo lo pongo para ejemplificar com se haría esto usando la STL.

En el programa utilizo funciones de la STL para encontrar el valor menor y el valor mayor en el vector original sin tener que ordenarlo.

Aquí está el código
Archivo grafica_barrash.cpp

#include <iostream>
#include <vector>
#include <algorithm>
#include <math.h>

using namespace std;

int main()
{
 int i_x=0, i_y=0;
 double dbl_valor=0, dbl_escala=0;
 vector<double> v_valores, v_ordenados;
 vector<double>::iterator v_valores_it, v_ordenados_it;
 vector<double>::const_iterator menor_it, mayor_it, valor_it;

 cout << "Teclee un número, (cualquier número negativo para terminar):" << endl;
 /* Mientras el usuario teclee números positivos (incluido el cero), guardamos en el vector
    v_valores los números que el usuario va tecleando
 */
 while (dbl_valor >= 0)
       {
        cin >> dbl_valor;
        if (dbl_valor >= 0)
            v_valores.push_back(dbl_valor);
       }

 cout << endl << "Estos son los números que Ud. introdujo:" << endl;
 // Muestra los valores almacenados en el vector v_valores
 for ( v_valores_it = v_valores.begin(); v_valores_it != v_valores.end(); v_valores_it++)
      cout << *v_valores_it << endl;

 // Hace el vector v_ordenados del mismo tamaño que el vector v_valores
 v_ordenados.resize (v_valores.size());
 // Copia los valores del vector v_valores al vector v_ordenados
 copy (v_valores.begin(), v_valores.end(), v_ordenados.begin());
 // Ordena el vector v_ordenados
 std::sort(v_ordenados.begin(), v_ordenados.end());

 cout << endl << "Estos son los números ordenados:" << endl;
 // Muestra los valores almacenados en el vector v_ordenados
 for ( v_ordenados_it = v_ordenados.begin(); v_ordenados_it != v_ordenados.end(); v_ordenados_it++)
      cout << *v_ordenados_it << endl;

 menor_it = min_element(v_valores.begin(), v_valores.end());
 mayor_it = max_element(v_valores.begin(), v_valores.end());

 cout << endl << "El valor menor es: " << *menor_it << endl;
 cout << "El valor mayor es: " << *mayor_it << endl;

 // Obtiene la escala
 dbl_escala = *mayor_it - *menor_it;
 cout << "La escala es: " << dbl_escala << endl << endl;

 for (i_x=0; i_x<8; i_x++)
      cout << " ";

 cout << ceil(*menor_it);
 for (i_x=0; i_x<=34; i_x++)
      cout << " ";
 cout << ceil((dbl_escala/2)+*menor_it);
 for (i_x=0; i_x<=34; i_x++)
      cout << " ";
 cout << ceil(*mayor_it);
 cout << endl;
 for (i_x=0; i_x<8; i_x++)
      cout << " ";
 cout << "|";
 for (i_x=0; i_x<=34; i_x++)
      cout << " ";
 cout << "|";
 for (i_x=0; i_x<=34; i_x++)
      cout << " ";
 cout << "|" << endl;

 // Dibuja las barras
 i_x=1;
 for ( v_valores_it = v_valores.begin(); v_valores_it != v_valores.end(); v_valores_it++)
     {
      cout << "Valor"<< i_x;
      /* Si el valor de x es de un sólo dígito, deja 2 espacios antes de empezar a dibujar la barra, de lo contrario
         deja sólo uno
      */
      cout << (i_x < 10 ? "  " : " ");
      valor_it = v_valores_it;
      for (i_y=1; i_y<= ((double)(*valor_it - *menor_it)/dbl_escala)*72+1; i_y++)
           cout << "*";
      cout << endl;
      i_x++;
     }

 return 0;
}

A continuación pongo una captura de pantalla
Como se puede ver, la gráfica muestra los valores como fueron introducidos por el usuario, así que:
valor1 = 100, valor2 = 40, valor3 = 75, valor4 = 50,valor5 = 25, valor6 = 30, valor7 = 10

Esto porque recibí un correo de una persona que dijo ser estudiante y me reclamaba que “estaba todo mal” y le habían puesto 1 de calificación.
En primer lugar, como la captura de pantalla demuestra, el programa funciona bien; en segundo lugar, este blog no es para que eviten hacer su tarea si son estudiantes; y en tercer lugar, las críticas constructivas a cualquier post que publique, son bienvenidas, pero si como en este caso, sólo escribe tonterías como “esta todo mal” y no aporta argumentos de en que se basa para hacer tal afirmación, es obvio que voy a ignorarlo.
Por último, mis post generalmente serán para personas con conocimientos mínimos de programación, por lo menos que sepan deducir un algoritmo a partir del código fuente que leen.

Tablas Hash multivalores en Qt

marzo 15, 2010

Tablas Hash

Una tabla hash es una estructura de datos que asocia llaves o claves con valores. Almacena pares (llave, valor) y proporciona una búsqueda muy rápida del valor asociado a una llave.

Supongamos que queremos tener una tabla hash que contenga una lista de alumnos con sus respectivas edades. En Qt podemos utilizar la clase QHash para crear una tabla hash de la siguiente forma:

QHash<QString, int> alumnos;

Con la instrucción anterior creamos una tabla hash llamada alumnos en donde la llave es de tipo QString (para almacenar el nombre del alumno) y el valor es de tipo entero (para almacenar la edad del alumno).  Para almacenar la información en la tabla hash llamada alumnos que acabamos de crear podemos usar algo como:


alumnos.insert(“Juan”, 20);
alumnos.insert(“Laura”, 22);
alumnos.insert(“Pedro”, 21);

Si queremos almacenar la edad de Laura en una variable llamada edad_laura, utilizamos la siguiente instrucción:

int edad_laura = alumnos.value(“Laura”);

Tablas Hash multivalores

Son tablas hash que permiten almacenar múltiples valores con la misma llave.

Supongamos que queremos almacenar en una estructura, los números de matrícula de todos los alumnos que están inscritos en una materia determinada. En Qt podemos hacerlo con la instrucción siguiente:

QMultiHash<QString, int> inscritos;

Con la instrucción anterior creamos una tabla hash multivalores llamada inscritos en donde la llave es de tipo QString (para almacenar el nombre de la materia) y el valor es de tipo entero (para almacenar el número de matrícula del alumno).  Para almacenar la información podemos usar algo como:

inscritos.insert(“Software Libre 1”, 456);
inscritos.insert(“Software Libre 1”, 924);
inscritos.insert(“Primeros pasos en GNU/Linux”, 621);
inscritos.insert(“Software Libre 1”, 285);
inscritos.insert(“Primeros pasos en GNU/Linux”, 456);

Si queremos recuperar los números de matrícula de todos los alumnos inscritos en la materia Software Libre 1, podemos usar la función values, que regresa una lista que podemos almacenar en un objeto de tipo QList para poder recorrerla posteriormente.

Qlist<int> matriculas_sl = inscritos.values(“Software Libre 1”);

Renombrar archivos usando C++ en GNU/Linux

mayo 8, 2009

En GNU/Linux (en los sistemas operativos tipo Unix en general, incluidos FreeBSD, etc.) no es recomendable manejar nombres de archivo que contengan espacios.

Puede darse el caso de que copiemos desde otro sistema operativo archivos que contienen espacios en su nombre, a nuestra máquina con GNU/Linux. Entónces, ¿qué hacer en esos casos?

Efectivamente… “lo recomendable” es renombrarlos para eliminar los espacios que contiene el nombre de archivo. Como puede ser una cantidad considerable de archivos, nos tomaría mucho tiempo ir renombrando archivo por archivo.

Exísten diferentes opciones para automatizar esa tarea, haciendo un script para bash, utilizando AWK y muchas otras soluciones.

A continuación un programa en C++ al que le podemos enviar una lista de directorios para que renombre todos los archivos que se encuentran en ellos eliminando los espacios del nombre de archivo.

/****************************************
* Archivo: renombrar_archivos.cpp               
* Autor  : SALOMON RINCON TORRES       
* Fecha  : 08/05/2009 (dd/mm/yyyy)
*/

#include
#include
#include
#include

using namespace std;

string QuitaEspacios(string s_cadena)
{
 string s_aux;

 for (int i_pos = 0; i_pos < s_cadena.length(); i_pos++)      {        if (s_cadena[i_pos] != ' ')            s_aux += s_cadena[i_pos];      }  return s_aux; } int main (int argc, char *argv[]) {  DIR *dirh;  struct dirent *dirp;  string s_dir, s_nombre, s_nuevonombre;  int i_renombrados = 0, i_ok = 0, i_fallos = 0; for(int i = 1; i < argc; i++) { s_dir = argv[i]; i_renombrados = 0; i_ok = 0; i_fallos = 0; cout << "******************** Directorio \"" << s_dir << "\" ********************\n" << endl; if ((dirh = opendir(s_dir.c_str())) == NULL) perror("No se pudo accesar al directorio "); else { for (dirp = readdir(dirh); dirp != NULL; dirp = readdir(dirh)) { s_nombre = dirp->d_name;

// Checamo que no sea el directorio . o ..
if (s_nombre != “.” && s_nombre != “..”)
{
cout << "Archivo: " << s_nombre << endl; // Si el nombre del archivo tiene un espacio, lo renombramos if (s_nombre.find(" ") != string::npos) {            s_nuevonombre = QuitaEspacios(s_nombre); if (rename((s_dir+"/"+dirp->d_name).c_str(), (s_dir+”/”+s_nuevonombre).c_str()) == 0)
{
i_renombrados++;
cout << "   === Renombrado como: " << s_nuevonombre.c_str() << endl; } else { i_fallos++; perror("No se pudo renombrar"); } } /* if */ else { i_ok++; cout << "OK\n"; } } /* if */ } /* for */ closedir(dirh); cout << endl; cout << "--- Archivos renombrados: " << i_renombrados << endl; cout << "--- Archivos OK: " << i_ok << endl; cout << "--- Archivos que no se pudieron renombrar: " << i_fallos << endl << endl; } /* else */ } /* for */ return 0; } [/sourcecode]

Generación de números aleatorios

enero 13, 2009

Para generar números aleatorios en C++ se utiliza la función rand(). Si queremos que el número generado este entre un rango de números, debemos obtener el módulo del número máximo y sumarle 1.

Por ejemplo

rand() % 10;

Nos da un número aleatorio entre 0 y 9, si queremos que el número este entre 1 y 10 hacemos:

(rand() % 10) + 1;

Para evitar que cada vez obtengamos el mismo número, debemos inicializar la semilla antes de llamar a la función rand(), utilizando srand() y time(). Para utilizar time() debemos indicar #include <time.h>

Ejemplo:

#include
#include

using namespace std;

int main()
{
// Inicializa la semilla para los números aleatorios
srand(time(NULL));
// Genera 10 números aleatorios entre 1 y 100
for (int i = 0; i < 10; i++) cout<<"El número aleatorio "<< i+1 << " es "<< (rand() % 100)+1 <

Usando cadenas, vectores y estructuras con la STL

enero 12, 2009

La STL (Standard Template Library) http://www.sgi.com/tech/stl/ es una de las grandes ventajas que C++ tiene con respecto a C.

Invertir una cadena en C++ es algo muy simple; sólo hay que recorrer cada uno de los elementos del vector desde el último hasta el primero.

El código podría ser el siguiente:


#include <iostream>
#include <string>

using namespace std;

int main()
{
    string cadena = "Hola mundo!";
    string aux_cadena = "";

    for (int i = cadena.size(); i >=0 ; i--)
         aux_cadena += cadena[i];

    cout<<"El texto normal es: "<<cadena<<endl;
    cout<<"El texto invertido es: "<<aux_cadena<<endl;
    return 0;
}
&#91;/sourcecode&#93;

Entre otras cosas, la STL contiene muchos algoritmos ya programados que podemos usar y que nos facilitan mucho trabajo.

Como ejemplo, a continuación muestro como podríamos hacer un programa para invertir una cadena usando la STL, para ello utilizaremos el algoritmo "reverse". Para utilizar los algoritmos de la STL, debemos poner #include &lt;algorithm&gt; en nuestro programa.

&#91;sourcecode language='cpp'&#93;

#include <iostream>
#include <string>
#include <algorithm>

using namespace std;

int main()
{
    string cadena = "Hola mundo!";
    string aux_cadena(cadena.begin(), cadena.end());
    reverse(aux_cadena.begin(), aux_cadena.end());

    cout<<"El texto normal es: "<<cadena<<endl;
    cout<<"El texto invertido es: "<<aux_cadena<<endl;
    return 0;
}
&#91;/sourcecode&#93;

Con la STL también podemos crear arreglos (vectores) sin indicar su tamaño, esto es útil porque probablemente no sepamos de antemano el número de elementos que vaya a contener el arreglo y queremos ir agregando elementos en tiempo de ejecución.
Para usar vectores debemos poner #include &lt;vector&gt; en nuestro programa.

El siguiente programa pide al usuario que introduzca números y los va almacenando en un vector, el programa termina cuando el usuario introduce el número cero.
Al final se recorre el vector y se muestran los números que el usuario introdujo.

&#91;sourcecode language='cpp'&#93;
#include <iostream>
#include <vector>

using namespace std;

int main()
{
    int i_numero=1;
    vector<int> v_enteros;
    vector<int>::iterator v_enteros_it;

    cout << "Teclee un número, (0 para terminar):" << endl;
    // Mientras el usuario teclee números diferentes de cero, guardamos en el vector los números que el usuario va tecleando
    while (i_numero != 0)
          {
              cin >> i_numero;
              if (i_numero != 0)
                  v_enteros.push_back(i_numero);
          }

    cout << endl << "Estos son los números que Ud. introdujo:" << endl;
    // Muestra los valores de los enteros almacenados en el vector
    for ( v_enteros_it = v_enteros.begin(); v_enteros_it != v_enteros.end(); v_enteros_it++)
         cout << *v_enteros_it << endl;        

    return 0;
}
&#91;/sourcecode&#93;

La forma adecuada de recorrer un vector es utilizando un iterador, tal y como se muestra en el programa anterior, aunque podemos recorrerlo como si se tratase de un arreglo.
El programa anterior modificado para no usar un iterador quedaría asi:

&#91;sourcecode language='cpp'&#93;
#include <iostream>
#include <vector>

using namespace std;

int main()
{
    int i_numero=1;
    vector<int> v_enteros;    

    cout << "Teclee un número, (0 para terminar):" << endl;
    // Mientras el usuario teclee números diferentes de cero, guardamos en el vector los números que el usuario va tecleando
    while (i_numero != 0)
          {
              cin >> i_numero;
              if (i_numero != 0)
                  v_enteros.push_back(i_numero);
          }

    cout << endl << "Estos son los números que Ud. introdujo:" << endl;
    // Muestra los valores de los enteros almacenados en el vector
    for (unsigned int i = 0; i < v_enteros.size(); i++)
         cout << v_enteros&#91;i&#93; << endl;

    return 0;
}
&#91;/sourcecode&#93;

<strong>Vector de objetos</strong>

Podemos crear también vectores de objetos, como ejemplo utilizaremos una clase muy sencilla que podría ser utilizada para guardar información de los diferentes departamentos en una empresa.
En el archivo de cabecera (el archivo .hpp) pondríamos algo como lo siguiente:


class Departamento
{
public:

Departamento(string, string, double); // constructor con parámetros para inicialización
Departamento();                 // constructor
~Departamento();                // destructor

void asignarID(string);
string obtenerID();
void asignarNombre(string);
string obtenerNombre();
void asignarPresupuesto(double);
double obtenerPresupuesto();

private:

string str_id;
string str_nombre;
double dbl_presupuesto;
};

El archivo que contendrá la implementación de los métodos (el archivo .cpp) podría contener un código como el mostrado a continuación:

//=============== CLASE Departamento ===============

void Departamento::asignarID(string id)
{
    str_id = id;
};

string Departamento::obtenerID()
{
    return str_id;
};

void Departamento::asignarNombre(string nombre)
{
    str_nombre = nombre;
};

string Departamento::obtenerNombre()
{
    return str_nombre;
};

void Departamento::asignarPresupuesto(double presupuesto)
{
    dbl_presupuesto = presupuesto;
};

double Departamento::obtenerPresupuesto()
{
    return dbl_presupuesto;
};

//--------------------------------------------------------------------------
// Constructor con parámetros para inicialización
Departamento::Departamento(string id_depto, string nombre_depto, double presupuesto)
{
 str_id = id_depto;
 str_nombre = nombre_depto;
 dbl_presupuesto = presupuesto;
}

//--------------------------------------------------------------------------
// Constructor vacío (default)
Departamento::Departamento()
{ }

//--------------------------------------------------------------------------
// Destructor
Departamento::~Departamento()
{ }

En un programa en el que quisiéramos crear objetos de la clase Departamento, deberíamos hacer el include del archivo .hpp que contiene la definición de la clase y para hacer un vector con objetos de esa clase, debemos hacer también #include <vector>.
Podríamos usar un código como el siguiente para crear un vector con 3 objetos de la clase Departamento:

vector<Departamento> v_deptos;

// Objeto de la clase Departamento
Departamento aux_depto;

// Variables auxiliares para capturar departamento
string aux_iddepto="";
string aux_nombredepto="";
double aux_presupuesto=0;

// Capturamos 3 departamentos y los agregamos al vector v_deptos
    for (int i = 0; i < 3; i++)
        {
            cout << "ID departamento " << i+1 << " : ";
            cin >> aux_iddepto;
            cout << "Nombre departamento " << i+1 << " : ";
            cin >> aux_nombredepto;
            cout << "Presupuesto departamento " << i+1 << " : ";
            cin >> aux_presupuesto;

            aux_depto.asignarID(aux_iddepto);
            aux_depto.asignarNombre(aux_nombredepto);
            aux_depto.asignarPresupuesto(aux_presupuesto);
            v_deptos.push_back(aux_depto);
        }

Para mostrar en pantalla los datos de todos los objetos almacenados en el vector podemos hacer una función que reciba como parámetro el vector:

//--------------------------------------------------------------------------
// Muestra los valores de los objetos almacenados en el vector de departamentos
void MuestraVectorDeptos(vector<Departamento> &tmp_deptos)
{
    vector<Departamento>::iterator tmp_iterator;

    cout << "****** Vector de departamentos ******" << endl;
    for ( tmp_iterator = tmp_deptos.begin(); tmp_iterator != tmp_deptos.end(); tmp_iterator++)
        {
         cout << "ID departamento: " << tmp_iterator->obtenerID() << "\t";
         cout << "Nombre departamento: " << tmp_iterator->obtenerNombre() << "\t";
         cout << "Presupuesto departamento: " << tmp_iterator->obtenerPresupuesto() << endl;
        }
    cout << "Total de Departamentos: " << tmp_deptos.size() << endl;
    cout << endl;
}
&#91;/sourcecode&#93;

<strong>Estructuras con campos tipo vector</strong>

Podemos crear estructuras que contengan algún campo de tipo vector.
Para entenderlo mejor, imaginemos que deseamos tener almacenados en un vector los datos de todos los departamentos de la empresa (para lo cual utilizaremos el código anterior), pero además queremos tener en otro vector, los datos de los empleados de la empresa y saber a que departamento pertenece cada empleado.
Además queremos poder obtener de una forma sencilla, un listado de los departamentos indicando que empleados están asignados a cada departamento.

Utilizaremos la clase Departamento que ya definimos y crearemos otra clase llamada Empleado.

Pondré en un archivo llamado cl_empresa.hpp la definición de las clases (Departamento y Empleado)


/* Archivo: cl_empresa.hpp            */

#include <string>

using namespace std;

//--------------------------------------------------------------------------
// Clase Departamento
class Departamento
{
    public:

     Departamento(string, string, double); // constructor con parámetros para inicialización
     Departamento();                 // constructor
     ~Departamento();                // destructor

     void asignarID(string);
     string obtenerID();
     void asignarNombre(string);
     string obtenerNombre();
     void asignarPresupuesto(double);
     double obtenerPresupuesto();

    private:

     string str_id;
     string str_nombre;
     double dbl_presupuesto;
};

//--------------------------------------------------------------------------
// Clase Empleado
class Empleado
{
    public:

     Empleado(int, string, double, string); // constructor con parámetros para inicialización
     Empleado();                 // constructor
     ~Empleado();                // destructor

     void asignarNumero(int);
     int obtenerNumero();
     void asignarNombre(string);
     string obtenerNombre();
     void asignarSueldo(double);
     double obtenerSueldo();
     void asignarIDdepa(string);
     string obtenerIDdepa();

    private:

     int i_numemp;
     string str_nombre;
     double dbl_sueldo;
     string str_iddepa;
};

La implementación de los métodos así como los constructuroes, etc. de ambas clases los pondré en un archivo cl_empresa.cpp

/* Archivo: cl_empresa.cpp            */

#include <string>
#include "cl_empresa.hpp"

//=============== CLASE Departamento ===============

void Departamento::asignarID(string id)
{
    str_id = id;
};

string Departamento::obtenerID()
{
    return str_id;
};

void Departamento::asignarNombre(string nombre)
{
    str_nombre = nombre;
};

string Departamento::obtenerNombre()
{
    return str_nombre;
};

void Departamento::asignarPresupuesto(double presupuesto)
{
    dbl_presupuesto = presupuesto;
};

double Departamento::obtenerPresupuesto()
{
    return dbl_presupuesto;
};

//--------------------------------------------------------------------------
// Constructor con parámetros para inicialización
Departamento::Departamento(string id_depto, string nombre_depto, double presupuesto)
{
 str_id = id_depto;
 str_nombre = nombre_depto;
 dbl_presupuesto = presupuesto;
}

//--------------------------------------------------------------------------
// Constructor vacío (default)
Departamento::Departamento()
{ }

//--------------------------------------------------------------------------
// Destructor
Departamento::~Departamento()
{ }

//=============== CLASE Empleado ===============

void Empleado::asignarNumero(int numero)
{
    i_numemp = numero;
};

int Empleado::obtenerNumero()
{
    return i_numemp;
};

void Empleado::asignarNombre(string nombre)
{
    str_nombre = nombre;
};

string Empleado::obtenerNombre()
{
    return str_nombre;
};

void Empleado::asignarSueldo(double sueldo)
{
    dbl_sueldo = sueldo;
};

double Empleado::obtenerSueldo()
{
    return dbl_sueldo;
};

void Empleado::asignarIDdepa(string id)
{
    str_iddepa = id;
};

string Empleado::obtenerIDdepa()
{
    return str_iddepa;
};

//--------------------------------------------------------------------------
// Constructor con parámetros para inicialización
Empleado::Empleado(int nempleado, string nombre_emp, double sueldo, string departamento)
{
 i_numemp = nempleado;
 str_nombre = nombre_emp;
 dbl_sueldo = sueldo;
 str_iddepa = departamento;
}

//--------------------------------------------------------------------------
// Constructor vacío (default)
Empleado::Empleado()
{ }

//--------------------------------------------------------------------------
// Destructor
Empleado::~Empleado()
{ }

Necesitaremos una estructura con 2 campos, uno para guardar el identificador del departamento y el otro será un vector que contendrá los números de empleado de todos los empleados que pertenezcan al departamento.

typedef struct empleadosxdepto_s
{
 string str_iddepto;
 vector<int> v_numerosemp;
} empleadosxdepto_t;

El programa principal contendrá una lista (en lugar de un vector) en donde almacenaremos las estructuras correspondientes a cada departamento.

Crearemos una función que nos permita agregar un empleado a un departamento; la función recibirá el código de departamento, el número de empleado y la lista que contiene las estructuras del tipo empleadosxdepto_t. Primero buscará en la lista de estructuras la que corresponda al código de departamento que recibe como parámetro, si la encuentra agrega al vector v_numerosemp de dicha estructura el número de empleado que recibe como parámetro, si no la encuentra, agrega primero la estructura y después el número de empleado a su vector v_numerosemp.

También agregamos una función para mostrar la información de la lista de estructuras.

El programa principal quedaría como sigue:

/* Archivo: empresa.cpp               */

#include <iostream>
#include <string>
#include <vector>
#include
	<list>
#include "cl_empresa.hpp"

using namespace std;

typedef struct empleadosxdepto_s
{
 string str_iddepto;
 vector<int> v_numerosemp; 
} empleadosxdepto_t;

//--------------------------------------------------------------------------
/* Agrega un empleado al vector que contiene los empleados de un departamento determinado
   Recibe como parámetros el código del departamento, el número de empleado,
   y la lista de empleados por departamento (en donde se va a insertar el número de empleado)
*/
void AgregaEmpleado(string id_depart, int i_empleado, list<empleadosxdepto_t> &lista)
{
    bool bl_encontrado = false;
    list<empleadosxdepto_t>::iterator tmp_iterator;
    /* Creamos una estructura auxiliar de tipo empleadosxdepto_t para almacenar los datos antes de agregar
       la estructura a la lista
    */
    empleadosxdepto_t tmp_sempleados;

    /* Busca en la lista el código de departamento que recibe como parámetro.
       Si lo encuentra, agrega el número de empleado que recibe como parámetro al vector de empleados que le corresponde a dicho departamento
       Si no lo encuentra, primero agrega el departamento y despues el número de empleado a su vector de empleados correspondiente
    */
    for ( tmp_iterator = lista.begin(); tmp_iterator != lista.end(); tmp_iterator++)
        { 
            if( (*tmp_iterator).str_iddepto == id_depart)
              {                  
                (*tmp_iterator).v_numerosemp.push_back(i_empleado);
                bl_encontrado = true;
                break;
              } /* if */
        } /* for */

    if (!bl_encontrado)
       {
           tmp_sempleados.str_iddepto = id_depart;
           tmp_sempleados.v_numerosemp.push_back(i_empleado);
           lista.push_back(tmp_sempleados);
       } /* if */       
}

//--------------------------------------------------------------------------
// Muestra los valores de los objetos almacenados en el vector de departamentos
void MuestraVectorDeptos(vector<Departamento> &tmp_deptos)
{
    vector<Departamento>::iterator tmp_iterator;

    cout << "****** Vector de departamentos ******" << endl;
    for ( tmp_iterator = tmp_deptos.begin(); tmp_iterator != tmp_deptos.end(); tmp_iterator++)
        { 
         cout << "ID departamento: " << tmp_iterator->obtenerID() << "\t";
         cout << "Nombre departamento: " << tmp_iterator->obtenerNombre() << "\t";
         cout << "Presupuesto departamento: " << tmp_iterator->obtenerPresupuesto() << endl;
        } 
    cout << "Total de Departamentos: " << tmp_deptos.size() << endl;
    cout << endl;
}

//--------------------------------------------------------------------------
// Muestra los valores de los objetos almacenados en el vector de empleados
void MuestraVectorEmps(vector<Empleado> &tmp_emps)
{
    vector<Empleado>::iterator tmp_iterator;

    cout << "****** Vector de empleados ******" << endl;
    for ( tmp_iterator = tmp_emps.begin(); tmp_iterator != tmp_emps.end(); tmp_iterator++)
        { 
         cout << "Número empleado: " << tmp_iterator->obtenerNumero() << "\t";
         cout << "Nombre empleado: " << tmp_iterator->obtenerNombre() << "\t";
         cout << "Sueldo empleado: " << tmp_iterator->obtenerSueldo() << "\t";
         cout << "ID departamento: " << tmp_iterator->obtenerIDdepa() << endl;
        } 
    cout << "Total de Empleados: " << tmp_emps.size() << endl;
    cout << endl;
}

//--------------------------------------------------------------------------
// Muestra los valores de las estructuras tipo empleadosxdepto_t almacenadas en la lista de empleados por departamento
void EmpleadosxDepartamento(list<empleadosxdepto_t> &lista)
{
    int i_departementos = 0, i_empleados = 0;
    int i_x = 0;    

    list<empleadosxdepto_t>::iterator tmp_iterator;

    cout << "****** Empleados por departamento ******" << endl;
    for ( tmp_iterator = lista.begin(); tmp_iterator != lista.end(); tmp_iterator++)
        {
         i_departementos++;
         cout << "ID Departamento: "<< (*tmp_iterator).str_iddepto << "\t";
         cout << "Número empleado: " << endl;

         i_x = (*tmp_iterator).v_numerosemp.size();
         for (int i_contador = 0; i_contador < i_x; i_contador++)         
             {
              cout << "\t\t\t\t" << (*tmp_iterator).v_numerosemp&#91;i_contador&#93; << endl;
             } /* for */
         cout << "\t\t\t" << "Total: "<< i_x << endl;
         i_empleados+=i_x;
        } /* for */
    cout << "Departamentos con almenos un empleado: "<< i_departementos << endl;
    cout << "Total de Empleados: "<< i_empleados << endl;
    cout << endl;
}

//--------------------------------------------------------------------------
// Programa principal
int main()
{
    vector<Departamento> v_deptos;    
    vector<Empleado> v_empleados;
    vector<Empleado>::iterator v_empleados_it;
    list<empleadosxdepto_t> l_empleados;    

    // Objeto de la clase Departamento
    Departamento aux_depto;
    // Objeto de la clase Empleado
    Empleado aux_emp;

    // Variables auxiliares para capturar departamento
    string aux_iddepto="";
    string aux_nombredepto="";
    double aux_presupuesto=0;

    // Variables auxiliares para capturar empleado
    int aux_nemp=0;
    string aux_nombreemp="";
    double aux_sueldo=0;    

    // Capturamos 3 departamentos y los agregamos al vector v_deptos
    for (int i = 0; i < 3; i++)
        {
            cout << "ID departamento " << i+1 << " : ";
            cin >> aux_iddepto;
            cout << "Nombre departamento " << i+1 << " : ";
            cin >> aux_nombredepto;
            cout << "Presupuesto departamento " << i+1 << " : ";
            cin >> aux_presupuesto;

            aux_depto.asignarID(aux_iddepto);
            aux_depto.asignarNombre(aux_nombredepto);
            aux_depto.asignarPresupuesto(aux_presupuesto);
            v_deptos.push_back(aux_depto);
        }

    // Capturamos 10 empleados y los agregamos al vector v_empleados
    for (int i = 0; i < 10; i++)
        {
            cout << "Número empleado " << i+1 << " : ";
            cin >> aux_nemp;
            cout << "Nombre empleado " << i+1 << " : ";
            cin >> aux_nombreemp;
            cout << "Sueldo empleado " << i+1 << " : ";
            cin >> aux_sueldo;
            cout << "ID departamento :";
            cin >> aux_iddepto;

            aux_emp.asignarNumero(aux_nemp);
            aux_emp.asignarNombre(aux_nombreemp);
            aux_emp.asignarSueldo(aux_sueldo);
            aux_emp.asignarIDdepa(aux_iddepto);
            v_empleados.push_back(aux_emp);
        }

    // Llena la lista que contiene los códigos de departamento y los números de cada una de sus empleados
    // Recorremos el vector de empleados
    for ( v_empleados_it = v_empleados.begin(); v_empleados_it != v_empleados.end(); v_empleados_it++)
         AgregaEmpleado(v_empleados_it->obtenerIDdepa(), v_empleados_it->obtenerNumero(), l_empleados);

    MuestraVectorDeptos(v_deptos);
    MuestraVectorEmps(v_empleados);
    EmpleadosxDepartamento(l_empleados);

    return 0;
}