2011-10-16 23 views
15

Estoy tratando de obtener algunos parámetros de entrada de usuario desde la consola, dos cadenas, dos ints y un doble. El código en cuestión Estoy intentando utilizar es la siguiente:C++ getline() no está esperando la entrada de la consola cuando se llama varias veces

#include <string> 
#include <iostream> 
using namespace std; 

// ... 

string inputString; 
unsigned int inputUInt; 
double inputDouble; 

// ... 

cout << "Title: "; 
getline(cin, inputString); 
tempDVD.setTitle(inputString); 

cout << "Category: "; 
getline(cin, inputString); 
tempDVD.setCategory(inputString); 

cout << "Duration (minutes): "; 
cin >> inputUInt; 
tempDVD.setDuration(inputUInt); 

cout << "Year: "; 
cin >> inputUInt; 
tempDVD.setYear(inputUInt); 

cout << "Price: $"; 
cin >> inputDouble; 
tempDVD.setPrice(inputDouble); 

Sin embargo, cuando se ejecuta el programa, en lugar de esperar a que el primer inputString a ser introducido, el código no se detiene hasta el segundo getline() llamada . Así, la salida de la consola se ve así:

Título: Categoría:

con el cursor que aparece después de la categoría. Si ingreso ahora, el programa salta a la entrada del año y no me permite ingresar más de una cadena. ¿Que esta pasando aqui?

+0

no puede reproducir; por favor, publique un código real y completo. Apuesto a que tu problema está en otro lado. Además, no mezcle la entrada formateada y 'getline()'. –

+0

@KerrekSB: Estoy de acuerdo en que mezclarlos es un síntoma de mal estilo, pero ¿cuál es el motivo objetivo para no mezclarlos? Creo que es perfectamente válido mezclarlos, realmente. – sehe

+0

@sehe: El problema es que la extracción formateada no consume las nuevas líneas, por lo que es muy fácil obtener resultados inesperados cuando haces 'getline()' después de pensar que ya procesaste toda la línea anterior. No digo que sea imposible, pero a menudo hace que la lógica sea muy difícil de leer y mantener. –

Respuesta

16

El problema es que está llamadas a getline() con el uso del operador >> mezcla.

Recuerde que el operador >> ignoró el espacio en blanco inicial, por lo que continuará correctamente a través de los límites de las líneas. Pero deja de leer después de que la entrada se ha recuperado correctamente y, por lo tanto, no se traga los caracteres '\ n' posteriores. Por lo tanto, si usas getline() después de >> normalmente obtienes lo incorrecto a menos que seas cuidadoso (para eliminar primero el carácter '\ n' que no fue leído).

El truco es no utilizar ambos tipos de entrada. Elija el adecuado y quédese con él.

Si son todos los números (u objetos que funcionan bien con el operador >>) entonces simplemente use el operador >> (Note cadena es el único tipo fundamental que no es simétrico con entrada/salida (es decir, no juega bien) .

Si la entrada contiene cadenas o una combinación de cosas que requerirán getline(), entonces solo use getline() y analice el número de la cadena.

std::getline(std::cin, line); 
std::stringstream linestream(line); 

int value; 
linestream >> value; 

// Or if you have boost: 
std::getline(std::cin, line); 
int value = boost::lexical_cast<int>(line); 
7

Debe vaciar el búfer de entrada. Se puede hacer con cin.clear(); cin.sync();.

3

Uso cin.clear() como se mencionó y uso adecuado manejo de errores:

cin.clear(); 
    cin.sync(); 

    cout << "Title: "; 
    if (!getline(cin, inputString)) exit 255; 
    tempDVD.setTitle(inputString); 

    cout << "Category: "; 
    if (!getline(cin, inputString)) exit 255; 
    tempDVD.setCategory(inputString); 

    cout << "Duration (minutes): "; 
    if (!(cin >> inputUInt)) exit 255; 
    tempDVD.setDuration(inputUInt); 

    cout << "Year: "; 
    if (!(cin >> inputUInt)) exit 255; 
    tempDVD.setYear(inputUInt); 

    cout << "Price: $"; 
    if (!(cin >> inputDouble)) exit 255; 
    tempDVD.setPrice(inputDouble); 
+1

Gracias. El código solo funciona si se usan cin.clear() y luego cin.sync(). – user754852

+0

La manera más fácil de mezclar el operador >> con el método getline() es ingresar cin.ignore() antes de cualquier llamada a getline para que el búfer de entrada se borre de cualquier carácter de línea nuevo de la entrada anterior. –

0

Mixing getline() con flujos de entrada en general, es algo malo que hacer. Teóricamente es posible manejar manualmente los búferes sucios que quedan con las transmisiones, pero es un dolor innecesario que definitivamente debe evitarse.

Será mejor que utilice una biblioteca de consola para obtener su entrada, de esta manera el trabajo sucio puede abstraerse para usted.

Eche un vistazo a TinyCon. Puede usar el método estático tinyConsole :: getLine() para reemplazar sus llamadas a getline y stream, y puede usarlo tantas veces como desee.

Puede encontrar información aquí: https://sourceforge.net/projects/tinycon/

4

Puede utilizar

cin.ignore(); 

o uso como @kernald mencionado

cin.clear(); 
cin.sync(); 

antes de usar getline()

Cuestiones relacionadas