Por qué usamos:
1) cin. Ignorar
2) cin.clear
?
Simplemente:
1) Para ignorar (extraer y descartar) valores que no queremos en la secuencia
2) Para borrar el estado interno de la secuencia. Después de usar cin.clear, el estado interno se establece nuevamente en goodbit, lo que significa que no hay 'errores'.
Versión larga:
Si algo se pone en 'stream' (cin), entonces debe tomarse desde allí. Por "tomado" nos referimos a "usado", "eliminado", "extraído" de la secuencia. La corriente tiene un flujo. Los datos fluyen en cin como agua en una corriente. Simplemente no puede detener el flujo de agua;)
Mira el ejemplo:
string name;
cout << "Give me your name and surname:"<<endl;
cin >> name;
int age;
cout << "Give me your age:" <<endl;
cin >> age;
¿Qué sucede si el usuario responde: "Arkadiusz Wlodarczyk" a la primera pregunta?
Ejecute el programa para verlo usted mismo.
Verá en la consola "Arkadiusz" pero el programa no le preguntará por 'edad'. Simplemente terminará inmediatamente después de imprimir "Arkadiusz".
Y no se muestra "Wlodarczyk". Parece como si se hubiera ido (?) *
¿Que pasó? ;-)
Porque hay un espacio entre "Arkadiusz" y "Wlodarczyk".
El carácter de "espacio" entre el nombre y el apellido es un signo para la computadora de que hay dos variables esperando ser extraídas en el flujo de 'entrada'.
La computadora piensa que está intentando enviar a la entrada más de una variable. Ese signo de "espacio" es un signo para que él lo interprete de esa manera.
Entonces, la computadora asigna "Arkadiusz" a 'nombre' (2) y, debido a que pones más de una cadena en el flujo (entrada), la computadora intentará asignar el valor "Wlodarczyk" a la variable 'edad' (!). El usuario no tendrá la oportunidad de poner nada en el 'cin' en la línea 6 porque esa instrucción ya se ejecutó (!). ¿Por qué? Porque todavía quedaba algo en marcha. Y como dije anteriormente, la corriente está en un flujo, por lo que todo debe eliminarse lo antes posible. Y la posibilidad llegó cuando la computadora vio la instrucción en la edad;
La computadora no sabe que usted creó una variable que almacena la edad de alguien (línea 4). 'edad' es simplemente una etiqueta. En el caso de las computadoras, la 'era' también podría llamarse: 'afsfasgfsagasggas' y sería lo mismo. Para él, es solo una variable a la que intentará asignar "Wlodarczyk" porque usted ordenó / indicó a la computadora que lo hiciera en la línea (6).
Está mal hacerlo, pero ¡eres tú quien lo hizo! ¡Es tu culpa! Bueno, tal vez usuario, pero aún así ...
Bien, bien. ¡¿Pero cómo solucionarlo ?!
Intentemos jugar un poco con ese ejemplo antes de arreglarlo correctamente para aprender algunas cosas más interesantes :-)
Prefiero hacer un enfoque donde entendamos las cosas. Arreglar algo sin saber cómo lo hicimos no da satisfacción, ¿no crees? :)
string name;
cout << "Give me your name and surname:"<<endl;
cin >> name;
int age;
cout << "Give me your age:" <<endl;
cin >> age;
cout << cin.rdstate();
Después de invocar el código anterior, notará que el estado de su secuencia (cin) es igual a 4 (línea 7). Lo que significa que su estado interno ya no es igual a goodbit. Algo está mal. Es bastante obvio, ¿no? Intentó asignar un valor de tipo de cadena ("Wlodarczyk") a la variable de tipo int 'edad'. Los tipos no coinciden. Es hora de informar que algo anda mal. Y la computadora lo hace cambiando el estado interno del flujo. Es como: "Jodido hombre, arréglame por favor. Te informo 'amablemente' ;-)"
Simplemente ya no puede usar 'cin' (stream). Está atorado. Como si hubieras puesto grandes troncos de madera en una corriente de agua. Debes arreglarlo antes de poder usarlo. Los datos (agua) ya no se pueden obtener de esa corriente (cin) porque el tronco de madera (estado interno) no le permite hacerlo.
Entonces, si hay un obstáculo (troncos de madera), ¿podemos simplemente eliminarlo con herramientas diseñadas para hacerlo?
¡Si!
El estado interno de cin establecido en 4 es como una alarma que aúlla y hace ruido.
cin.clear borra el estado y vuelve a la normalidad (goodbit). Es como si hubieras venido y silenciado la alarma. Solo lo pospones. Sabes que algo pasó, entonces dices: "Está bien dejar de hacer ruido, ya sé que algo anda mal, cállate (claro)".
¡Muy bien, hagámoslo! Usemos cin.clear ().
Invoque el siguiente código usando "Arkadiusz Wlodarczyk" como primera entrada:
string name;
cout << "Give me your name and surname:"<<endl;
cin >> name;
int age;
cout << "Give me your age:" <<endl;
cin >> age;
cout << cin.rdstate() << endl;
cin.clear();
cout << cin.rdstate()<< endl;
Seguramente podemos ver después de ejecutar el código anterior que el estado es igual a goodbit.
Genial, ¿el problema está resuelto?
Invoque el siguiente código usando "Arkadiusz Wlodarczyk" como primera entrada:
string name;
cout << "Give me your name and surname:"<<endl;
cin >> name;
int age;
cout << "Give me your age:" <<endl;
cin >> age;
cout << cin.rdstate() << endl;;
cin.clear();
cout << cin.rdstate() << endl;
cin >> age;
Incluso aunque el estado se establezca en goodbit después de la línea 9, no se le pregunta al usuario por "edad". El programa se detiene.
¡¿POR QUÉ?!
Oh hombre ... Acabas de apagar la alarma, ¿qué pasa con el tronco de madera dentro del agua? * Vuelve al texto donde hablamos sobre "Wlodarczyk" cómo supuestamente se fue.
Tienes que quitar "Wlodarczyk" ese trozo de madera del arroyo. Apagar las alarmas no resuelve el problema en absoluto. ¿Lo acaba de silenciar y cree que el problema se ha ido? ;)
Entonces es hora de otra herramienta:
cin.ignore se puede comparar con un camión especial con cuerdas que viene y quita los troncos de madera que atascaron el arroyo. Elimina el problema que creó el usuario de su programa.
Entonces, ¿podríamos usarlo incluso antes de que suene la alarma?
Si:
string name;
cout << "Give me your name and surname:"<< endl;
cin >> name;
cin.ignore(10000, '\n');
int age;
cout << "Give me your age:" << endl;
cin >> age;
El "Wlodarczyk" se eliminará antes de hacer ruido en la línea 7.
¿Qué es 10000 y '\ n'?
Dice eliminar 10000 caracteres (por si acaso) hasta que se cumpla '\ n' (ENTRAR). Por cierto, se puede hacer mejor usando numeric_limits pero no es el tema de esta respuesta.
Entonces, la principal causa del problema desapareció antes de que se hiciera ruido ...
Entonces, ¿por qué necesitamos "claro"?
¿Qué pasaría si alguien hubiera preguntado "dame tu edad" en la línea 6, por ejemplo: "veinte años" en lugar de escribir 20?
Los tipos no vuelven a coincidir. La computadora intenta asignar una cadena a int. Y comienza la alarma. Ni siquiera tienes la oportunidad de reaccionar en una situación como esa. cin.ignore no te ayudará en un caso así.
Así que debemos usar clear en un caso así:
string name;
cout << "Give me your name and surname:"<< endl;
cin >> name;
cin.ignore(10000, '\n');
int age;
cout << "Give me your age:" << endl;
cin >> age;
cin.clear();
cin.ignore(10000, '\n');
Pero, ¿debería limpiar el estado 'por si acaso'?
Por supuesto no.
Si algo sale mal (cin >> age;), la instrucción le informará devolviendo false.
Entonces podemos usar una declaración condicional para verificar si el usuario ingresó el tipo incorrecto en la secuencia
int age;
if (cin >> age)
cout << "You put integer";
else
cout << "You bad boy! it was supposed to be int";
De acuerdo, podemos solucionar nuestro problema inicial como, por ejemplo, que:
string name;
cout << "Give me your name and surname:"<< endl;
cin >> name;
cin.ignore(10000, '\n');
int age;
cout << "Give me your age:" << endl;
if (cin >> age)
cout << "Your age is equal to:" << endl;
else
{
cin.clear();
cin.ignore(10000, '\n');
cout << "Give me your age name as string I dare you";
cin >> age;
}
Por supuesto, esto se puede mejorar, por ejemplo, haciendo lo que hizo en cuestión usando loop while.
PRIMA:
Quizás se esté preguntando. ¿Qué pasa si quisiera obtener el nombre y el apellido en la misma línea del usuario? ¿Es posible usar cin si cin interpreta cada valor separado por "espacio" como una variable diferente?
Claro, puedes hacerlo de dos formas:
1)
string name, surname;
cout << "Give me your name and surname:"<< endl;
cin >> name;
cin >> surname;
cout << "Hello, " << name << " " << surname << endl;
2) o usando la función getline.
getline(cin, nameOfStringVariable);
y así es como se hace:
string nameAndSurname;
cout << "Give me your name and surname:"<< endl;
getline(cin, nameAndSurname);
cout << "Hello, " << nameAndSurname << endl;
La segunda opción puede ser contraproducente en caso de que la use después de usar 'cin' antes de getline.
Vamos a ver:
una)
int age;
cout << "Give me your age:" <<endl;
cin >> age;
cout << "Your age is" << age << endl;
string nameAndSurname;
cout << "Give me your name and surname:"<< endl;
getline(cin, nameAndSurname);
cout << "Hello, " << nameAndSurname << endl;
Si pone "20" como edad, no se le pedirá nameAndSurname.
Pero si lo haces de esa manera:
segundo)
string nameAndSurname;
cout << "Give me your name and surname:"<< endl;
getline(cin, nameAndSurname);
cout << "Hello, " << nameAndSurname << endl;
int age;
cout << "Give me your age:" <<endl;
cin >> age;
cout << "Your age is" << age << endll
todo esta bien.
¡¿QUÉ?!
Cada vez que pones algo en la entrada (flujo), dejas al final el carácter blanco que es ENTER ('\ n'). Tienes que ingresar valores de alguna manera en la consola. Entonces debe suceder si los datos provienen del usuario.
b) las características de cin es que ignora los espacios en blanco, por lo que cuando está leyendo información de cin, el carácter de nueva línea '\ n' no importa. Se ignora.
a) la función getline obtiene la línea completa hasta el carácter de nueva línea ('\ n'), y cuando el carácter de nueva línea es lo primero, la función getline obtiene '\ n', y eso es todo. Extrae el carácter de nueva línea que dejó en la transmisión el usuario que puso "20" en la transmisión en la línea 3.
Entonces, para arreglarlo es siempre invocar cin.ignore (); cada vez que use cin para obtener algún valor si alguna vez va a usar getline () dentro de su programa.
Entonces, el código adecuado sería:
int age;
cout << "Give me your age:" <<endl;
cin >> age;
cin.ignore();
cout << "Your age is" << age << endl;
string nameAndSurname;
cout << "Give me your name and surname:"<< endl;
getline(cin, nameAndSurname);
cout << "Hello, " << nameAndSurname << endl;
Espero que las transmisiones sean más claras para ti.
¡Ja, callame por favor! :-)