La entrada estándar std::cin
¶
En los apartados anteriores se ha aprendido a mostrar texto por pantalla. Sin embargo, eso no permite interaccionar a un usuario con un programa.
Una forma básica de interacción es aceptar datos en forma de texto vía teclado.
La biblioteca iostream
tiene una variable predefinida para un
flujo (stream) de caracteres de entrada llamada cin
(character input), lo que permite transformar secuencias de caracteres
a la representación binaria de datos en memoria.
Nótese que es el proceso inverso al de cout
, donde se transforma la representación binaria
de un dato a una secuencia de caracteres imprimibles.
#include <iostream>
int main()
{
std::cout << "Introduce un entero: ";
int x;
std::cin >> x;
std::cout << "x=" << x << '\n';
}
Edita, compila y ejecuta el código
Analicemos este programa:
#include <iostream>
informamos al compilador nuestro deseo de utilizar funciones de E/S.
int x
definimos la variable donde deseamos almacenar el valor introducido por teclado.
std::cin
la variable
cin
pertenece al espacio de nombresstd
.>>
operador de extracción, que permite extraer caracteres del flujo de entrada
cin
y transformarlos a su representación binaria interna.
Nota
Regla nemotécnica
Los operadores de extracción e inserción indican el sentido del flujo de datos. Así, sabiendo
que con cin
utilizamos el teclado y con cout
mostramos en la consola:
cin
>>
: los caracteres fluyen desde el tecladocout
<<
: los caracteres fluyen hacia la consola
La operación de extracción¶
La introducción de caracteres desde el teclado por parte del usuario es libre y, por tanto, sujeta a errores.
De cara a entender algunos de los errores que pueden producirse es importante conocer
cómo se produce el proceso de extracción mediante el operador >>
.
Podemos encontrarnos en las siguientes dos situaciones:
El búfer asociado a
cin
está vacío. Es la situación más habitual.El operador
>>
mantiene la ejecución del programa a la espera de la introducción de datos por parte del usuario.Cuando el usuario introduce el carácter
'\n'
, el operador>>
comienza a transformar los caracteres introducidos a la representación binaria interna de la variable.Todos los espacios en blanco (whitespace characters) al inicio del búfer son ignorados, incluidos tabuladores y retorno de línea.
Se transforman los caracteres hasta el siguiente espacio en blanco.
El resto de caracteres permanece en el búfer de
cin
hasta una nueva operación de extracción.
El búfer asociado a
cin
tiene datos. En este caso, el operador>>
comienza de forma inmediata la operación de extracción siguiendo las pautas descritas anteriormente respecto a la gestión de los espacios en blanco.
Veamos qué ocurre con el siguiente programa con distintos escenarios de introducción
de datos. Supondremos que el usuario decide introducir los valores 3
y 5
para
las variables x
e y
respectivamente.
#include <iostream>
int main()
{
std::cout << "Introduce un entero: ";
int x;
std::cin >> x;
std::cout << "Introduce otro entero: ";
int y;
std::cin >> y;
std::cout << "x=" << x << "\ny=" << y << '\n';
}
Edita, compila y ejecuta el código
Caso 1
Se muestra el mensaje
"Introduce un entero: "
El usuario pulsa
3
+'\n'
Se muestra el mensaje
"Introduce otro entero: "
El usuario pulsa
5
+'\n'
Se muestran por pantalla correctamente los valores de las variables
x
ey
Es el habitual y todo sucede como es de esperar.
Caso 2
Se muestra el mensaje
"Introduce un entero: "
El usuario pulsa
'\t'
+'\t'
+3
+'\n'
Se muestra el mensaje
"Introduce otro entero: "
El usuario pulsa
'\n'
+5
+'\n'
Se muestran por pantalla correctamente los valores de las variables
x
ey
El usuario ha introducido espacios en blanco al principio de cada una de las dos operaciones
de extracción. Aunque es algo inusual, no hay ningún error pues el operador >>
extrae
estos caracteres del búfer ignorándolos.
Caso 3
Se muestra el mensaje
"Introduce un entero: "
El usuario pulsa
3
+' '
+5
+'\n'
Se muestra el mensaje
"Introduce otro entero: x=3"
Se muestra por pantalla
"y=5"
En este caso, el usuario se ha precipitado y ha introducido inicialmente los dos valores
separados por un espacio, 3 5'\n'
. ¡Ese es el contenido del búfer en ese momento!
Lo que ocurre es lo siguiente:
El operador de extracción, tras introducir el carácter
'\n'
comienza el proceso de transformación, que se ve interrumpido por la presencia del espacio en blanco' '
.A continuación, se muestra el mensaje
"Introduce otro entero: "
.Comienza el proceso de extracción para la variable
y
, pero ahora el búfer decin
no está vacío, está formado por la cadena"5'\n'"
.Se extrae correctamente el valor
5
hacia la variabley
.Comienza el proceso de inserción del búfer de
cout
. Nótese que, como no se ha introducido ningún carácter nueva línea, la cadena"x=3"
aparece a continuación de la cadena"Introduce otro entero: "
.
En definitiva, las variables x
e y
tienen los valores deseados, aunque el proceso
ha sido atípico y los datos de salida en la consola muestran un aspecto desordenado.
Caso 4
Se muestra el mensaje
"Introduce un entero: "
El usuario pulsa
a
+3
+'\n'
Se muestra el mensaje
"Introduce otro entero: x=0"
Se muestra el mensaje
"y=0"
En este caso, el usuario se ha equivocado y ha introducido un carácter, a
, que el operador
de extracción es incapaz de transformar a entero. A partir de este momento, cin
pasa a
modo fallo (failure) y cualquier proceso de extracción posterior es obviado.
Las variables oportunas se inicializan a 0
por defecto.
Es una situación de error en el programa y el funcionamiento de este será normalmente indefinido, con resultados espurios.
Caso 5
Se muestra el mensaje
"Introduce un entero: "
El usuario pulsa
3
+a
+'\n'
Se muestra el mensaje
"Introduce otro entero: x=3"
Se muestra el mensaje
"y=0"
Es un caso similar al anterior. En este caso, el operador de extracción es capaz de
transformar el 3
, pero a partir de este momento entra en modo fallo.
Atención
La gestión de este tipo de errores debidos a la incorrecta introducción de datos por parte del usuario es fundamental en cualquier programa comercial.
Ejemplos típicos los vemos en el relleno de formularios en páginas web, donde el programa se asegura que un número de cuenta, un DNI, etc. tiene el formato correcto.
Detectar caracteres o formatos erróneos, es una tarea relativamente compleja y sale del ámbito de la asignatura. Por ello, no lo abordaremos en este curso.
Sin embargo, conocer el proceso de extracción del operador >>
puede arrojar luz
para entender el porqué de resultados absurdos cuando se ejecuta un programa.
Introducción de más de un valor en la misma línea¶
El operador de extracción puede aparecer concatenado, evaluándose de izquierda a derecha.
#include <iostream>
int main()
{
std::cout << "Introduce dos enteros: ";
int x, y;
std::cin >> x >> y;
std::cout << "x=" << x << "\ny=" << y << '\n';
}
Edita, compila y ejecuta el código
Sería el escenario descrito en el Caso 3, con una introducción de valores
por parte del usuario como 3
+ ' '
+ 5
+ '\n'
.