No busques más por todo internet porque has llegado al espacio exacto, tenemos la solución que necesitas encontrar y sin problema.
Solución:
los cin.clear()
borra la bandera de error en cin
(para que las futuras operaciones de E / S funcionen correctamente), y luego cin.ignore(10000, 'n')
salta a la siguiente nueva línea (para ignorar cualquier otra cosa en la misma línea que el no número para que no cause otro error de análisis). Solo saltará hasta 10000 caracteres, por lo que el código asume que el usuario no ingresará una línea muy larga e inválida.
Entras en el
if (!(cin >> input_var))
declaración si ocurre un error al tomar la entrada de cin. Si se produce un error, se activa un indicador de error y fallarán los intentos futuros de obtener información. Es por eso que necesitas
cin.clear();
para deshacerse de la bandera de error. Además, la entrada que falló estará ubicada en lo que supongo que es una especie de búfer. Cuando intente obtener una entrada nuevamente, leerá la misma entrada en el búfer y fallará nuevamente. Es por eso que necesitas
cin.ignore(10000,'n');
Saca 10000 caracteres del búfer pero se detiene si encuentra una nueva línea ( n). El 10000 es solo un gran valor genérico.
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; //line 1
cout << "Give me your name and surname:"<> name;//line 3
int age;//line 4
cout << "Give me your age:" <> age;//line 6
¿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 la “edad”. Simplemente terminará inmediatamente después de imprimir “Arkadiusz”.
Y no se muestra “Wlodarczyk”. Parece como si se hubiera ido (?) *
¿Qué sucedió? 😉
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á tratando de 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 ingresó más de una string en la corriente (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 surgió 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:"<> name;
int age;
cout << "Give me your age:" <> age;
cout << cin.rdstate(); //new line is here :-)
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? Intentaste asignar string escriba valor ("Wlodarczyk") para int tipo de variable '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: "Maldito 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 un chorro 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.
Ah, entonces, si hay un obstáculo (troncos de madera), ¿podemos eliminarlo con herramientas diseñadas para hacerlo?
¡Sí!
El estado interno de cin establecido en 4 es como una alarma que está aullando y haciendo 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)".
¡Está 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:"<> name;
int age;
cout << "Give me your age:" <> age;
cout << cin.rdstate() << endl;
cin.clear(); //new line is here :-)
cout << cin.rdstate()<< endl; //new line is here :-)
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:"<> name;
int age;
cout << "Give me your age:" <> age;
cout << cin.rdstate() << endl;;
cin.clear();
cout << cin.rdstate() << endl;
cin >> age;//new line is here :-)
Incluso aunque el estado se establezca en bit bueno después de la línea 9, no se le preguntará 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.
Necesitas 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 se atascaron en el arroyo. Elimina el problema que creó el usuario de su programa.
Entonces, ¿podríamos usarlo incluso antes de que suene la alarma?
Sí:
string name;
cout << "Give me your name and surname:"<< endl;
cin >> name;
cin.ignore(10000, 'n'); //time to remove "Wlodarczyk" the wood log and make the stream flow
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 ...
¿Por qué necesitamos 'claro' entonces?
¿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 string 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'); //time to remove "Wlodarczyk" the wood log and make the stream flow
int age;
cout << "Give me your age:" << endl;
cin >> age;
cin.clear();
cin.ignore(10000, 'n'); //time to remove "Wlodarczyk" the wood log and make the stream flow
Pero, ¿debería limpiar el estado 'por si acaso'?
Por supuesto no.
Si algo sale mal (cin >> age;), la instrucción se lo 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) //it's gonna return false if types doesn't match
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'); //time to remove "Wlodarczyk" the wood log and make the stream flow
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'); //time to remove "Wlodarczyk" the wood log and make the stream flow
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:
Puede que te lo estés 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 la línea de obtención.
Vamos a ver:
a)
int age;
cout << "Give me your age:" <> 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:
B)
string nameAndSurname;
cout << "Give me your name and surname:"<< endl;
getline(cin, nameAndSurname);
cout << "Hello, " << nameAndSurname << endl;
int age;
cout << "Give me your age:" <> 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 lleva toda la línea 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:" <> age;
cin.ignore(); // it ignores just enter without arguments being sent. it's same as cin.ignore(1, 'n')
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.
¡Hah, callame por favor! 🙂
Si haces scroll puedes encontrar los informes de otros usuarios, tú igualmente tienes la opción de mostrar el tuyo si lo crees conveniente.