Leer caracteres y cadenas de caracteres en C++

Método get() para leer un carácter
Para leer por teclado datos que están separados por espacios en blanco o intro se puede usar el operador de extracción >> sobre cin. Pero si queremos leer caracteres incluidos espacios en blanco o el intro este operador no nos sirve.En ese caso podemos utilizar el método get.
La forma de uso es:
cin.get(caracter);
El método get extrae de cin un carácter y lo guarda en la variable. Si el carácter extraído es el de fin de fichero se activa el indicador de fin de fichero.
Si el buffer de entrada está vacío, cuando llega a esta instrucción el programa se detiene esperando que se teclee un carácter y se pulse intro.
Por ejemplo, el siguiente programa lee un carácter por teclado y muestra su código ASCII.
#include <iostream>
using namespace std;
int main(void)
{
    char c;
    cout <<  "Introduce un caracter: ";
    cin.get(c);
    cout << "ASCII de " << c << " -> " << static_cast<int>(c) << endl;
    system("pause");
}
El método get extrae del flujo caracteres incluso el intro. En algunas ocasiones leer el intro que puede tener efectos no deseados.
En el siguiente programa vemos un ejemplo en el que el carácter intro que queda en el buffer después de introducir un entero hace que el programa no funcione como esperamos. Este programa lee un número entero y muestra si es par o impar y a continuación lee un carácter y muestra si es una letra minúscula:
#include <iostream>
using namespace std;
int main(void)
{
  char c;
  int num;
  //leemos un número entero
  cout <<  "Introduce un numero entero: ";
  cin >> num;
  cout << "El numero es " << ((num%2==0)? "par" : "impar") << endl;
  //leemos un carácter
  cout <<  "Introduce un caracter: ";
  cin.get(c);
  cout << "El caracter" << ((c>='a' and c<='z')?" es ":" no es");
  cout << " una letra minuscula" << endl;
  system("pause");
}
la ejecución de este programa es la siguiente:


Tras el mensaje “Introduce un carácter” el programa no espera a que se teclee y muestra directamente el mensaje “El carácter no es una letra minúscula”. Esto ocurre porque cuando se ha introducido el valor 18 realmente en el flujo de entrada está ese valor más el intro que hemos pulsado:
Flujo de entrada cin:  18\n
Mediante la instrucción cin >> num; se le asigna a num el valor 18. Este valor se extrae de cin pero el \n permanece:
Flujo de entrada después de leer el entero:  \n
Cuando el programa llega a la instrucción cin.get(c); extrae de cin el intro y se lo asigna a c. No se detiene la ejecución del programa para que se introduzca el carácter y se produce un resultado no deseado.
Para evitar esto, en estos casos es necesario limpiar el buffer con el método ignore.
El programa modificado, limpiando el intro para que funcione correctamente es:
#include <iostream>
using namespace std;
int main(void)
{
  char c;
  int num;
  //leemos un número entero
  cout <<  "Introduce un numero entero: ";
  cin >> num;
  cout << "El numero es " << ((num%2==0)? "par" : "impar") << endl;

  //limpiamos el buffer de entrada
  cin.ignore(numeric_limits<int>::max(),'\n');

  //leemos un carácter
  cout <<  "Introduce un caracter: ";
  cin.get(c);
  cout << "El caracter" << ((c>='a' and c<='z')? " es ":" no es");
  cout << " una letra minuscula" << endl;
  system("pause");
}

Método getline() para leer una cadena de  caracteres
El operador >> sobre cin no es útil para leer cadenas de caracteres que contengan espacios en blanco.
Por ejemplo,  para leer en un programa el nombre y apellidos de una persona, si utilizamos las siguientes instrucciones:
char nombre[50];  // cadena de caracteres de longitud máxima 50
...
cout << "Introduce tu nombre: ";
cin >> nombre
...
Si tecleamos Lucas Alonso Guzman, a la variable nombre solo se le asignará Lucas ya que a continuación se encuentra un espacio en blanco y el operador >> entiende que es el final de la asignación.
Para evitar esto se utiliza el método getline.
La forma general de uso es:
cin.getline(cadena, num, carácter_final);
getline lee una serie de caracteres desde el flujo de entrada y los almacena en la variable cadena. Se leen caracteres hasta el final del flujo, hasta el primer carácter que coincide con el carácter_final especificado, el cual se desecha ó hasta que se han leído num-1 caracteres; en este último caso el estado del flujo pasa a ser de fallo. Esto se puede comprobar con el método fail(). El estado de fallo se produce porque se han leído num-1 caracteres que es el máximo que queremos leer y aun han quedado caracteres en el flujo por lo que es posible que se hayan tecleado más caracteres de la cuenta y pueden provocar un error en la siguiente lectura.
getline añade automáticamente el carácter nulo (\0) al final de la cadena extraída.
Utilizando getline para leer nombre y apellidos del ejemplo anterior escribiremos:
cin.getline(nombre, 50, '\n');
El carácter final se puede omitir, si no aparece se supone que es \n :
cin.getline(nombre, 50);
Ejemplos de lectura de caracteres en C++
Ejemplo 1: El siguiente ejemplo muestra la diferencia cuando se leen cadenas de caracteres en C++ usando o no getline:
#include <iostream>
using namespace std;
int main(void)
{
      char nombre[40];
      cout <<  "Introduce nombre y apellidos: ";
      cin.getline(nombre,40);  //lectura incluyendo espacios
      cout << "Hola " << nombre << endl;
      cout <<  "Introduce nombre y apellidos: ";
      cin >> nombre;  //lectura sin incluir espacios
      cout << "Hola " << nombre << endl;
      system("pause");
}
La salida de este programa es:


Ejemplo 2:
En el siguiente ejemplo se leen cadenas de caracteres hasta que se pulsa F6. Se comprueba y se muestra el estado del flujo cin después de cada lectura.

#include <iostream>
using namespace std;
int main(void)
{  char cadena[15];
   cout << "Introduzca cadena de caracteres. F6 Para finalizar\n\n";
   do
   {  cout << "cadena: ";
      cin.getline(cadena,15,'\n');
   
      //se muestran los bits de estado del flujo cin para
      //comprobar el resultado de la lectura

      cout << "bit eof->" << cin.eof() << " ";
      cout << "  bit fail->" << cin.fail() << endl;
             
      //si la cadena excede de 15 cin.fail() toma el valor 1
     
      //si no se ha pulsado F6 en el nombre (fin de lectura)
      //y el nombre excede de la longitud máxima permitida
      //se eliminan el resto de los caracteres
      if(!cin.eof() && cin.fail())
      {
            cin.clear();
            cin.ignore(numeric_limits<int>::max(),'\n');
      }
   }while(!cin.eof());
   system("pause");
}
La salida de este programa es la siguiente:

6 comentarios:

  1. ¿Sabes como hacer la cadena de caracteres con espacio usando 'STRING'?

    ResponderEliminar
  2. y se pueden usar en arreglos bidimencionales?

    ResponderEliminar
  3. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  4. printf("Ingrese edad: ");
    scanf("%d", &edad);
    cout << "\nIngrese sexo: ";
    cin.get(d);
    cout << "\nIngrese carrera: ";
    cin.get(carrera);

    ResponderEliminar
  5. Hola como estan. Excelente Tutorial. Por favor necesito de su ayuda. Quisiera que un programa guarde datos dentro de un registro, pero sin teclar en el teclado, es decir que el dato o la palabra que quiero guardar en el registro (dentro de un archivo), este escrito dentro del codigo del programa. Para guardar dentro del registro e estado usando gets (registro.Nombre). Muchas Gracias espero su respuesta.

    ResponderEliminar