Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: eleon en 2 Febrero 2012, 22:41 pm



Título: Se pierde el primer cin.getline en un analisis de casos
Publicado por: eleon en 2 Febrero 2012, 22:41 pm
Holas:

Tengo un pequeño problemilla y es que dentro de un analisis de casos (switch) no se me ejecuta el primer cin.getline(). Ejemplo:

Código
  1. switch (opcion)
  2.        {
  3.            case 1:
  4.                while (pEA->pSiguiente != 0)
  5.                {
  6.                    pEA = pEA->pSiguiente;
  7.                }
  8.  
  9.                pEA->pSiguiente = new agenda;
  10.                pEA = pEA->pSiguiente;
  11.  
  12.                cout << "Introduzca el nombre: ";
  13.                cin.getline (nuevoNombre, tamNombre); //Este cin.getline() no se ejecuta
  14.                pEA->configurarNombre (&nuevoNombre[0]);
  15.                cout << endl;
  16.  
  17.                cout << "Introduzca el correo: ";
  18.                cin.getline (nuevoCorreo, tamCorreo);
  19.                pEA->configurarCorreo (&nuevoCorreo[0]);
  20.                cout << endl;
  21.  
  22.               ...

He probado quitando la parte de "Introduzca el nombre" para comprobar que no es un error sintáctico y lo que sucede es que no se ejecuta el cin.getline del correo, es decir, el primer cin.getline del "case" se omite. Lo mismo me sucede en "case 2: " etc.

Para corroborarlo he probado a poner antes del "Introduzca el nombre" un cin.getline(cadena_prueba, 30), y entonces si que se ejecuta correctamente el del nombre.

¿Alguno sabe por qué el primero siempre se omite?.

Gracias y saludos.


Título: Re: Se pierde el primer cin.getline en un analisis de casos
Publicado por: rir3760 en 3 Febrero 2012, 00:40 am
En la gran mayoría de los casos el comportamiento que mencionas se debe a que, antes de la parte que se "salta", tienes una sentencia que lee un valor de la entrada estándar pero deja el '\n' en el bufer.

Por ejemplo:
Código
  1. string palabra;
  2. char linea[100];
  3.  
  4. // ...
  5.  
  6. cin >> palabra;
  7. cin.getline(linea, 100); // Esto se "salta"

Supongo es eso pero, para estar seguros, lo mejor es revisar el código fuente completo.

Un saludo


Título: Re: Se pierde el primer cin.getline en un analisis de casos
Publicado por: eleon en 3 Febrero 2012, 08:27 am
Gracias por responder, la única entrada que hay antes es esta:

Código
  1.    while (opcion != 5)
  2.    {
  3.        opcion = 0;
  4.        while (opcion < 1 || opcion > 5)
  5.        {
  6.            F_menu();
  7.            cin >> opcion; //Primera entrada en todo el programa
  8.            cout << endl;
  9.        }
  10.  
  11.        switch (opcion)
  12.        {
  13.            case 1:
  14.                while (pEA->pSiguiente != 0)
  15.                {
  16.                    pEA = pEA->pSiguiente;
  17.                }
  18.  
  19.                pEA->pSiguiente = new agenda;
  20.                pEA = pEA->pSiguiente;
  21.  
  22.                cout << "Introduzca el nombre: ";
  23.                cin.getline (nuevoNombre, tamNombre); // Entrada suprimida
  24.                pEA->configurarNombre (&nuevoNombre[0]);
  25.                cout << endl;
  26.  
  27.                cout << "Introduzca el correo: ";
  28.                cin.getline (nuevoCorreo, tamCorreo);
  29.                pEA->configurarCorreo (&nuevoCorreo[0]);
  30.                cout << endl;
  31. ...

¿Por qué mete un "\n" automáticamente en el buffer?, ¿y cuál sería la solución para evitarlo?.

EDITO: Por si ayuda te pongo el cuerpo del programa hasta donde se produce el error:

Código
  1. int main ()
  2. {
  3.    USHORT opcion;
  4.  
  5.    agenda objeto;
  6.    agenda *pEA = &objeto;
  7.    USHORT numContactos = 0;
  8.  
  9.    char nuevoNombre [tamNombre];
  10.    char nuevoCorreo [tamCorreo];
  11.    ULONG nuevoTelefono = 0;
  12.    ULONG nuevoMovil = 0;
  13.  
  14.    bool encontrado;
  15.    char nombre [tamNombre];
  16.    char correo [tamCorreo];
  17.    char *pNombre = 0;
  18.    char *pCorreo = 0;
  19.    USHORT contador;
  20.  
  21.    int i, j;
  22.  
  23.    while (opcion != 5)
  24.    {
  25.        opcion = 0;
  26.        while (opcion < 1 || opcion > 5)
  27.        {
  28.            F_menu();
  29.            cin >> opcion;
  30.            cout << endl;
  31.        }
  32.  
  33.        switch (opcion)
  34.        {
  35.            case 1:
  36.                while (pEA->pSiguiente != 0)
  37.                {
  38.                    pEA = pEA->pSiguiente;
  39.                }
  40.  
  41.                pEA->pSiguiente = new agenda;
  42.                pEA = pEA->pSiguiente;
  43.  
  44.                cout << "Introduzca el nombre: ";
  45.                cin.getline (nuevoNombre, tamNombre);
  46.                pEA->configurarNombre (&nuevoNombre[0]);
  47.                cout << endl;
  48.  
  49.                cout << "Introduzca el correo: ";
  50.                cin.getline (nuevoCorreo, tamCorreo);
  51.                pEA->configurarCorreo (&nuevoCorreo[0]);
  52.                cout << endl;
  53. ...

Una cosa en la que me acabo de fijar es en cómo inicializo las cadenas en el constructor de la clase; ¿es correcto de esta forma o quizá sea lo que produce el error?:

Código
  1. agenda::agenda()
  2. {
  3.    char nombre = {'\0'};
  4.    char correo = {'\0'};
  5.    telefono = 0;
  6.    movil = 0;
  7.  
  8.    pSiguiente = 0;
  9. }

Un saludo.


Título: Re: Se pierde el primer cin.getline en un analisis de casos
Publicado por: rir3760 en 3 Febrero 2012, 16:31 pm
El comportamiento es normal. Cuando se ejecuta la sentencia:
Código
  1. cin >> opcion;
Se toman los caracteres necesarios de la entrada estándar pero el '\n' se queda en el bufer.

A continuación se ejecuta:
Código
  1. cin.getline (nuevoNombre, tamNombre);
Y esa función espera "cero o mas caracteres seguidos del avance de linea", como ese ya se encuentra en el bufer se toma y procesa como un linea vacía.

Soluciones hay varias: una es descartar el resto de la linea justo después de la primera sentencia, otra opción es utilizar getline para todas las lecturas junto con la clase "stringstream" para obtener los valores (hay varios ejemplos de ello en la base de datos de los foros).

Un saludo


Título: Re: Se pierde el primer cin.getline en un analisis de casos
Publicado por: eleon en 3 Febrero 2012, 22:24 pm
Gracias por tu tiempo, he optado por usar "cin.ignore(1);" después del cin.

Saludos.


Título: Re: Se pierde el primer cin.getline en un analisis de casos
Publicado por: rir3760 en 4 Febrero 2012, 00:40 am
En tu caso eso funciona pero (casi) como un castillo de naipes. Para explicarlo mejor compila y ejecuta el programa. Cuando te pida la opción teclea:
Código:
123 {ENTER}
Eso es: 1, 2, 3, un espacio y la tecla {ENTER}.

Es por ello que se considera una mejor opción leer una linea almacenándola en un objeto de la clase "string" y a continuación "extraes" el numero mediante otro objeto de la clase "stringstream".

Un saludo