[C con Clase] Dudas sobre el uso del gets(), cin.getline()

Steven Davidson srd4121 en njit.edu
Jue Sep 8 11:44:24 CEST 2011


Hola Diego,

2011/9/8 Diego <diegoartesanal en gmail.com>:
> Buenas noches a todos nuevamente, heme aquí de nuevo con una duda que hace
> tiempo que no resuelvo.
>
> Siempre que utilizo el gets()  o el cin.getline() para obtener una cadena

Antes de continuar, quiero dejarte claro que la función 'gets()' no es
NADA recomendable; incluso los propios diseñadores de ANSI C/C++ no
recomiendan su uso. En su lugar, usa 'fgets()', aunque guarde el
carácter de fin-de-línea, '\n'.

En segundo lugar, si usas C++, no sea aconseja mezclar la
funcionalidad de ANSI C - 'printf()', 'scanf()', 'fgets()', 'puts()',
etc. - para manejar canales (streams, en inglés) con la de ANSI C++ -
'cout', cin', etc.. Al principio, ambas funcionalidades están
vinculadas a los mismos recursos, pero pueden desvincularse. Por
ejemplo, si se alteran su "configuración", no se puede tratar a los
mismos canales con ambas funcionalidades. Además, si vas a usar C++,
entonces sugiero que uses ANSI C++ - 'cin', 'cout', etc.;
especialmente si estás aprendiendo.

> con espacios (una dirección , un nombre compuesto, etc) ,me ocurre que al
> tratar de realizar un registro por ejemplo, se produce un 'salto de línea' .
>

Esto suele ser problema de la interpretación de la funcionalidad de
'cin' y 'scanf()' al tratar las cadenas de caracteres a leer. Si
indicas que se interprete los caracteres como un número entero,
entonces interpretará cuantos caracteres pueda. Cualesquier caracteres
posteriores, que no representen un entero, permanecen en el "búfer"
del canal de entrada. Por ejemplo,

short int nEdad;

cout << "¿Cuántos años tienes?  ";
cin >> nEdad;

char szNombre[64]="";
cout << "¿Cómo te llamas?  ";
cin >> szNombre;

cout << "Te llamas " << szNombre << " y tienes " << nEdad << " años" << endl;

Al ejecutar este programa, aparecerá esto:

¿Cuántos años tienes?  30[ENTER]
¿Cómo te llamas?
Te llamas  y tienes 30 años

Aparentemente, el programa ha saltado esa segunda pregunta. El
problema es que 'cin >>' no ha pedido datos al usuario, porque existen
datos a leer en el búfer del canal de entrada. Esto es lo que ocurre
al principio:

¿Cuántos años tienes?
búfer del canal de entrada := ""  (vacío)

El usuario escribe:  30[ENTER]
búfer del canal de entrada := "30\n"

Se interpreta los caracteres para "leer" y guardar un entero:  cin >> nEdad
nEdad <- 30
búfer del canal de entrada := "\n"

¿Cómo te llamas?
búfer del canal de entrada := "\n"

Se ejecuta:  cin >> szNombre, pero al existir caracteres en el canal
de entrada, no se piden caracteres al usuario, así que al final
tenemos,
szNombre <- ""
búfer del canal de entrada := ""  (vacío)


Por esta razón, el programa aparenta "saltarse" la lectura,
especialmente desde el punto de vista del usuario. La solución es
"limpiar" el canal de entrada extrayendo TODOS los caracteres para que
quede vacío y así forzar una lectura del usuario para que escriba más.

La solución puede ser simplemente usar una cadena de caracteres
auxiliar, justo después de una interpretación de caracteres; es decir,
no se han leído caracteres. Por ejemplo,

char szAux[10240];  // 10 KB
...
cin >> nEdad;
cin >> szAux;  // Leemos y extraemos hasta 10 mil y pico caracteres posteriores

Otra forma es simplemente usando una sola lectura y extracción del
siguiente carácter que sabemos que es el fin-de-línea; esto es,

cin >> nEdad;
cin.get();  // Extraemos '\n'

Para ser más profesionales, usa 'ignore()'; esto es,

cin >> nEdad;
cin.ignore();  // Extrae todos los caracteres hasta '\n'


Lo que NO aconsejo es usar 'fflush(stdin)', porque no es un
comportamiento estándar; algunos sistemas funcionará bien y en otros
no hará nada.


Espero haber aclarado la duda.

Steven




Más información sobre la lista de distribución Cconclase