Diario de un programador día 74
Lectura desde el teclado.
En esta ocasión se verá como solicitar información
al usuario, guardarla en una variable y luego mostrarla en pantalla. (Al igual
que en las clases anteriores con los otros lenguajes)
Para leer datos se utilizará el objeto de flujo de
entrada std::cin y el operador de extracción de flujo >> para obtener los
datos ingresados por el usuario.
std::cin
Para tratar de entender este objeto, se empezará
con un pequeño ejemplo, el cual solicitará un número entero y luego lo mostrará
en pantalla:
#include<iostream>
int main(){
int num1;
std::cout <<
"Ingresa un numero: ";
std::cin >> num1;
std::cout << "El numero
es: " << num1 << std::endl;
return 0;
}
Otro ejemplo. Esta vez se
solicitarán dos números, se sumarán y se mostrará el resultado en pantalla.
#include <iostream>
int main(void){
int num1, num2;
std::cout << "Ingresa un
numero ";
std::cin
>> num1;
std::cout << "Ingresa
otro numero ";
std::cin
>> num2;
std::cout << "La suma es
" << num1 + num2 << std::endl;
return 0;
}
Y aquí otro ejemplo, pero esta vez un número y una cadena:
#include <iostream>
int main(void){
int num1;
char palabra[20];
std::cout << "Ingresa un
numero ";
std::cin
>> num1;
std::cout << "Ingresa
una palabra ";
std::cin
>> palabra;
std::cout << "Numero:
" << num1 << std::endl;
std::cout << "Palabra:
" << palabra << std::endl;
return 0;
}
Esto al parecer se ve bien, se solicitó un número
y luego una palabra, entonces el resultado fue mostrado en pantalla. Hasta hora
todo bien pero, ¿si en vez de escribir una palabra escribo una frase?. Probaré
con una compuesta por dos palabras, utilizaré el reconocido mensaje
"hola mundo"... veamos:
La palabra "hola mundo" salió cortada,
imprimiendo solamente "hola". Esto mismo ocurre con scanf() en el
lenguaje C., lo que ocurre es que cin lee hasta encontrar un retorno de carro o
un espacio en blanco, por lo que al dejar el espacio entre "hola
mundo", simplemente ignoró todo lo que seguía después, dejando la parte
sobrante en el buffer (memoria). Una solución a este problema es utilizar cin.getline(variable,
nro.caracteres). Ejemplo:
#include <iostream>
int main(void){
char frase[50];
std::cout << "Ingresa una frase:
";
std::cin.getline(frase, 50);
std::cout << "Frase:
" << frase << std::endl;
return 0;
}
Muy bien!!! ahora si leyó la
frase completa. Bueno, ahora que ya se pueden leer frases, se tratará de
arreglar el programa anterior a ver qué sorpresa ocurre. En C, C++ es casi
"normal" que ocurran cosas inesperadas o que una vez que se arregla
una cosa, dos se echan a perder jajaja. A ver...
#include <iostream>
int main(void){
int num1;
char frase[50];
std::cout <<
"Ingresa un numero ";
std::cin >> num1;
std::cout << "Ingresa
una frase: ";
std::cin.getline(frase, 50);
std::cout << "Numero:
" << num1 << std::endl;
std::cout << "Frase:
" << frase << std::endl;
return 0;
}
A ver que
acaba de ocurrir. El programa no permitió que ingresara la frase,
"comiéndose" la instrucción siguiente. Esto ocurrió debido a que
cin.getline, tomó o leyó (como prefieras llamar) el retorno de carro de la
instrucción anterior que quedó almacenada en el buffer y la utilizó como si
fuese el carácter ingresado por mi (aunque en realidad, si lo ingresé, ya que
es la manera de aceptar el dato ingresado en la instrucción anterior, pero no
quería que fuese utilizado de esta manera). Para arreglar este inconveniente,
se puede utilizar cin.ignore(), el cual sirve para sacar o extraer lo que quedó
en el buffer, en este caso el "Enter" o retorno de carro.
#include <iostream>
int
main(void){
int num1;
char frase[50];
std::cout << "Ingresa un
numero ";
std::cin >> num1;
std::cin.ignore();
std::cout << "Ingresa una frase: ";
std::cin.getline(frase,
50);
std::cout << "Numero: " << num1 << std::endl;
std::cout << "Frase: " << frase <<
std::endl;
return
0;
}
Ahora sí.
El limpiar la memoria logró el resultado buscado.
Algo que
me he dado cuenta, es que estos errores de buffer, suceden a menudo que se
intercalan solicitudes de ingreso entre números y cadenas. Por ejemplo, si
solamente solicito datos numéricos, por lo general (siempre hay excepciones) no
hay problema. Por otra parte si solamente solicito cadenas, tampoco se producen
mayores inconvenientes. Colocaré un par de ejemplos de esto:
#include <iostream>
int main(void){
int num1, num2, num3;
std::cout << "Ingresa un
numero ";
std::cin >> num1;
std::cout << "Ingresa
otro numero ";
std::cin >> num2;
std::cout << "Ingresa el
ultimo numero ";
std::cin >> num3;
std::cout << "Numero 1: " << num1 <<
std::endl;
std::cout << "Numero 2: " << num2 <<
std::endl;
std::cout << "Numero 3: " << num3 <<
std::endl;
return 0;
}
No hubo
necesidad (aparente) de limpiar el buffer.
Otro
ejemplo. Ahora con cadenas.
#include <iostream>
int
main(void){
char cadena1[20], cadena2[20], cadena3[20];
std::cout << "Ingresa
una frase: ";
std::cin.getline(cadena1,20);
std::cout << "Ingresa
otra frase: ";
std::cin.getline(cadena2,20);;
std::cout << "Ingresa la
ultima frase: ";
std::cin.getline(cadena3,20);
std::cout << "Cadena 1:
" << cadena1 << std::endl;
std::cout << "Cadena 2:
" << cadena2 << std::endl;
std::cout << "Cadena 3:
" << cadena3 << std::endl;
return 0;
}
Como se
puede ver, esta vez cin.getline se "comporto de buena forma" y no se
"comió" el retorno de carro como sí ocurrió cuando se ingresó un dato
de tipo numérico.
Para
terminar esto del ingreso por teclado, cabe mencionar que C++ también acepta
las funciones de C, tales como scanf(), fgets() y varias más que rondan por
ahí. Otra que mencionaré antes de terminar es la clase string, la cual permite(entre muchas otras funciones) utilizar la función getline(std::cin, variable), la que permite también leer
frases. Un ejemplo de esta clase:
#include <iostream>
#include <string>
int main(void){
std::string frase;
std::cout << "Ingresa
una frase: ";
getline(std::cin, frase);
std::cout << "Frase: "
<< frase <<
std::endl;
return 0;
}
Poner
atención en la forma en que se declara la variable, se utiliza un std::string, no
siendo necesario declarar un arreglo a esa variable, ya que no es un arreglo de
caracteres.
Hay mucha
información en la web, lo malo es que no siempre es fácil de ubicar y muchas
veces paso horas tratando de solucionar problemas como estos presentados ahora.
Hasta la próxima.
Gustavo J. Cerda Nilo
Enero 2016, última actualización Mayo 2016