Discussion:
Entrada por teclado
(demasiado antiguo para responder)
Jose Luis Hernandez Toribio
2004-05-24 08:39:51 UTC
Permalink
Hola a todos,

mi problema creo que es fácil de solucionar pero aún no lo he conseguido de forma
óptima. Ahí va:

En cierto programa C (ANSI C, con gcc) al introducir la descripción de un artículo
sólo me coge la primera palabra, es decir, si quiero meter "cámara de vídeo" sólo se
queda con "cámara". ¿Qué función puedo utilizar para que coja todo? He probado con
fgets.

Otro problema. Cuando introduzco una opción de un menú (con scanf) y le doy a Enter
cuando va a otra pantalla y allí espero la introducción de otra opción, es como que
coge ese Enter anterior como introducido y aparece el mensaje de error que tengo
para que vuelva a introducir otra vez. Es decir, es como que guarda los retornos de
carro anteriores lo cual hace que se produzcan mensajes de error en pantallas
siguientes cuando no se ha introducido aún nada. He probado con getc y nada.
He probado con setbuf(stdin, NULL) y nada.

Supongo que serán chorradillas, pero no he dado con ellas.


Gracias.
garlito
2004-05-25 17:25:48 UTC
Permalink
Post by Jose Luis Hernandez Toribio
mi problema creo que es fácil de solucionar pero aún no lo he conseguido de forma
Yo estoy recien empezando con C, y he estado probando las funciones de
E/S, a ver si te puedo ayudar
Post by Jose Luis Hernandez Toribio
En cierto programa C (ANSI C, con gcc) al introducir la descripción de un artículo
sólo me coge la primera palabra, es decir, si quiero meter "cámara de vídeo" sólo se
queda con "cámara". ¿Qué función puedo utilizar para que coja todo? He probado con
fgets.
Lo he probado y funciona perfectamente, tando desde consola como desde
archivo, ¿ no estarás usando scanf ? Esta creo que usa el espacio para
cortar las cadenas

Por cierto, para consola está la función gets, pero gcc me da un aviso
de que es peligrosa y no debería usarla ¿ Alguien sabe por qué es esto ?
Post by Jose Luis Hernandez Toribio
Otro problema. Cuando introduzco una opción de un menú (con scanf) y le doy a Enter
cuando va a otra pantalla y allí espero la introducción de otra opción, es como que
coge ese Enter anterior como introducido y aparece el mensaje de error que tengo
para que vuelva a introducir otra vez. Es decir, es como que guarda los retornos de
carro anteriores lo cual hace que se produzcan mensajes de error en pantallas
siguientes cuando no se ha introducido aún nada. He probado con getc y nada.
He probado con setbuf(stdin, NULL) y nada.
Me he encontrado con el mismo problema, pero esto creo que es por la
entrada con buffer de UNIX, pasa igual con otros lenguajes. Lo que he
hecho es una función para limpiar el buffer. Si el último carácter leído
NO es un salto de línea, y no me interesa el resto del buffer, entonces
llamo a esta función:

void limpiar_entrada(void)
{
char c;
do
{
c = getchar();
} while (c != '\n');
}


Salu2
Alberto Giménez
2004-05-25 19:16:24 UTC
Permalink
Post by garlito
Por cierto, para consola está la función gets, pero gcc me da un aviso
de que es peligrosa y no debería usarla ¿ Alguien sabe por qué es esto ?
Porque es un nido de buffer overflows XD
- --
Luis Alberto Giménez
GnuPG ID: 0x3BAABDE1
garlito
2004-05-25 20:59:43 UTC
Permalink
Post by Alberto Giménez
Post by garlito
Por cierto, para consola está la función gets, pero gcc me da un aviso
de que es peligrosa y no debería usarla ¿ Alguien sabe por qué es esto ?
Porque es un nido de buffer overflows XD
okis, ahora veo la utilidad del segundo parámetro de fgets ;-)

Saludos
Alberto Giménez
2004-05-25 00:28:07 UTC
Permalink
Post by Jose Luis Hernandez Toribio
queda con "cámara". ¿Qué función puedo utilizar para que coja todo? He probado con
fgets.
fgets debería funcionar. Podrías pegar el código a ver...
Post by Jose Luis Hernandez Toribio
Otro problema. Cuando introduzco una opción de un menú (con scanf) y le doy a Enter
la familia *scanf maneja de una manera bastante penosa los saltos de
línea. Yo siempre utilizo fgets y algún parser de ser necesario (atoi,
atof, ...).

Saludos
- --
Luis Alberto Giménez
GnuPG ID: 0x3BAABDE1
Jose Luis Hernandez Toribio
2004-05-25 19:02:05 UTC
Permalink
Hola,

gracias por contestar. Creo que vas a tener razón con lo de que el fgets sí lo hace
bien, pero aún no lo he podido comprobar porque arrastro el problema de los retornos
de carro y me ha impedido probarlo.
Una duda que tengo con la función que muestras es en qué momento la utilizas. Si yo
por ejemplo, acabo de dar de alta un artículo y le doy el código 9 y meto Enter para
aceptar, ya coge ese Enter y me lo mete en la descripción, por tanto yo no puedo
meter nada ahí, me pasa al siguiente campo. Por tanto, en qué momento usas la
función que has escrito? además la función va aceptando teclas mientras no sea salto
de línea verdad? no entiendo muy bien su uso para este caso.

Lo que ponía de setbuf(stdin, NULL) si no me equivoco es para trabajar sin buffer,
todo va directo, pero sigo con el mismo problema.

Por cierto, gets es peligroso porque gets(char *s) lee una línea de stdin y la
guarda en el búfer al que apunta s hasta que se encuentre bien un carácter
terminador nueva-línea, bien EOF, al cual reemplaza con '\0'. No se hace ninguna
comprobación de desbordamiento del búfer. Por eso es peligroso, puede comprometer la
seguridad.

Un saludo.
Post by garlito
Post by Jose Luis Hernandez Toribio
mi problema creo que es fácil de solucionar pero aún no lo he conseguido de
forma
Post by garlito
Yo estoy recien empezando con C, y he estado probando las funciones de
E/S, a ver si te puedo ayudar
Post by Jose Luis Hernandez Toribio
En cierto programa C (ANSI C, con gcc) al introducir la descripción de un
artículo
Post by garlito
Post by Jose Luis Hernandez Toribio
sólo me coge la primera palabra, es decir, si quiero meter "cámara de vídeo"
sólo se
Post by garlito
Post by Jose Luis Hernandez Toribio
queda con "cámara". ¿Qué función puedo utilizar para que coja todo? He probado
con
Post by garlito
Post by Jose Luis Hernandez Toribio
fgets.
Lo he probado y funciona perfectamente, tando desde consola como desde
archivo, ¿ no estarás usando scanf ? Esta creo que usa el espacio para
cortar las cadenas
Por cierto, para consola está la función gets, pero gcc me da un aviso
de que es peligrosa y no debería usarla ¿ Alguien sabe por qué es esto ?
Post by Jose Luis Hernandez Toribio
Otro problema. Cuando introduzco una opción de un menú (con scanf) y le doy a
Enter
Post by garlito
Post by Jose Luis Hernandez Toribio
cuando va a otra pantalla y allí espero la introducción de otra opción, es como
que
Post by garlito
Post by Jose Luis Hernandez Toribio
coge ese Enter anterior como introducido y aparece el mensaje de error que tengo
para que vuelva a introducir otra vez. Es decir, es como que guarda los retornos
de
Post by garlito
Post by Jose Luis Hernandez Toribio
carro anteriores lo cual hace que se produzcan mensajes de error en pantallas
siguientes cuando no se ha introducido aún nada. He probado con getc y nada.
He probado con setbuf(stdin, NULL) y nada.
Me he encontrado con el mismo problema, pero esto creo que es por la
entrada con buffer de UNIX, pasa igual con otros lenguajes. Lo que he
hecho es una función para limpiar el buffer. Si el último carácter leído
NO es un salto de línea, y no me interesa el resto del buffer, entonces
void limpiar_entrada(void)
{
char c;
do
{
c = getchar();
} while (c != '\n');
}
Salu2
--


___________________________

José Luis Hernández Toribio
___________________________
garlito
2004-05-25 20:47:16 UTC
Permalink
Lo de limpiar el buffer lo hago para eliminar los carácteres sobrantes
de la respuesta del usuario y el salto de línea, cuando sólo me interesa
el primer carácter. Así la siguiente lectura no los pilla. No se si
habrá una forma mejor

Por ejemplo si quieres una respuesta del usuario en términos de sí o no,
o una letra que selecciona un menú, etc

Sería:

puts("Introducir un carácter: ");
c = getchar(); /* puede que el usario introduza más de un carácter, pero
sólo te intersa el primero */
if ( c != '\n' ) limpiar_linea();

puts("Introducir otro carácter: ");
c = getchar(); /* Si no has limpiado el buffer te toma el primer carácter
sobrante de la lectura anterior, o el salto de línea */


Cuando haces un scanf para leer por ejemplo un entero también pueden
quedar carácteres en el buffer de entrada si el usuario introduce
caráctereres detrás del número. Esto te estropeará una posterior lectura,
es decir, cuando le vuelves a preguntar para que te introduzca otra
cosa. Lo que ya no sé es como comprobar en este caso si el buffer quedó
vacío o no

Lo de setbuf, ni idea, ya lo probaré

Saludos
BitterB
2004-05-26 19:31:17 UTC
Permalink
Post by Jose Luis Hernandez Toribio
Hola,
gracias por contestar. Creo que vas a tener razón con lo de que el fgets
sí lo hace bien, pero aún no lo he podido comprobar porque arrastro el
problema de los retornos de carro y me ha impedido probarlo.
Personalmente para leer cadenas yo prefiero fgets, pero lo puedes hacer
tambien con scanf sin ningun problema. Echale un vistazo a la sintaxis de
scanf y sobre todo lo referente a la especificacion de formato de los datos
de entrada.
La diferencia principal entre fgets y scanf es que fgets leera datos hasta
encontrar un caracter nueva linea (\n), pero leera tambien este caracter
transformandolo en el indicador de fin de cadena. Sin embargo scanf leera
datos hasta encontrar un separador, que por defecto sera un espacio en
blanco (en este saco tambien entran tabuladores y caracteres nueva linea) y
este caracter NO lo lee, lo deja en el buffer. Scanf funciona asi
independientemente de que los datos de entrada sean enteros, caracteres o
cadenas.
Teniendo esto en cuenta, para leer una cadena que este formada por varias
palabras (separadas por espacios en blanco) no se puede hacer scanf("%s",
cadena) porque solo leera la primera palabra, sin embargo si que podrias
hacer algo como scanf("%[^\n]", cadena) esto seria algo asi como "lee todo
lo que te encuentres hasta llegar a un caracter nueva linea", y debes de
recordar que el caracter nueva linea se quedara en el buffer por lo que
deberias limpiarlo o recogerlo de alguna forma.
Post by Jose Luis Hernandez Toribio
Una duda que tengo con la función que muestras es en qué momento la
utilizas. Si yo por ejemplo, acabo de dar de alta un artículo y le doy el
código 9 y meto Enter para aceptar, ya coge ese Enter y me lo mete en la
descripción, por tanto yo no puedo meter nada ahí, me pasa al siguiente
campo.
Supongo que para leer el codigo del articulo usas algo como esto:
scanf("%i", &codigo) Por lo que segun te he dicho mas arriba sobre el
funcionamiento de scanf lo que haces es leer el codigo del articulo y dejar
en el buffer el caracter nueva linea del Enter, de esta forma cuando vas a
leer la descripcion del articulo lo que haces es coger este caracter nueva
linea que queda en el buffer. Para solucionarlo podrias hacer algo asi al
leer el codigo del articulo: scanf("%i%*c", &codigo) Pruebalo y ya me
contaras que tal te va, y si no te enteras de lo que significa "%i%*c" ya
sabes, a repasar la sintaxis de scanf.
Ah! una cosa mas, para leer cadenas con scanf y dejar el buffer limpio
tambien podrias hacer lo siguiente: scanf("%[\n]%*c", cadena) Esto leera la
cadena y eliminara el caracter nueva linea del buffer.
Tan solo hay que echarle imaginacion ;)

Saludos.
--
Vamos a crear una civilizacion de la mente en el ciberespacio. Que sea mas
humana y hermosa que el mundo que vuestros gobiernos han creado hasta
ahora.
Jose Luis Hernandez Toribio
2004-05-25 19:02:22 UTC
Permalink
Hola,

gracias por contestar. Creo que vas a tener razón con lo de que el fgets sí lo hace
bien, pero aún no lo he podido comprobar porque arrastro el problema de los retornos
de carro y me ha impedido probarlo.
Una duda que tengo con la función que muestras es en qué momento la utilizas. Si yo
por ejemplo, acabo de dar de alta un artículo y le doy el código 9 y meto Enter para
aceptar, ya coge ese Enter y me lo mete en la descripción, por tanto yo no puedo
meter nada ahí, me pasa al siguiente campo. Por tanto, en qué momento usas la
función que has escrito? además la función va aceptando teclas mientras no sea salto
de línea verdad? no entiendo muy bien su uso para este caso.

Lo que ponía de setbuf(stdin, NULL) si no me equivoco es para trabajar sin buffer,
todo va directo, pero sigo con el mismo problema.

Por cierto, gets es peligroso porque gets(char *s) lee una línea de stdin y la
guarda en el búfer al que apunta s hasta que se encuentre bien un carácter
terminador nueva-línea, bien EOF, al cual reemplaza con '\0'. No se hace ninguna
comprobación de desbordamiento del búfer. Por eso es peligroso, puede comprometer la
seguridad.

Un saludo.
Post by garlito
Post by Jose Luis Hernandez Toribio
mi problema creo que es fácil de solucionar pero aún no lo he conseguido de
forma
Post by garlito
Yo estoy recien empezando con C, y he estado probando las funciones de
E/S, a ver si te puedo ayudar
Post by Jose Luis Hernandez Toribio
En cierto programa C (ANSI C, con gcc) al introducir la descripción de un
artículo
Post by garlito
Post by Jose Luis Hernandez Toribio
sólo me coge la primera palabra, es decir, si quiero meter "cámara de vídeo"
sólo se
Post by garlito
Post by Jose Luis Hernandez Toribio
queda con "cámara". ¿Qué función puedo utilizar para que coja todo? He probado
con
Post by garlito
Post by Jose Luis Hernandez Toribio
fgets.
Lo he probado y funciona perfectamente, tando desde consola como desde
archivo, ¿ no estarás usando scanf ? Esta creo que usa el espacio para
cortar las cadenas
Por cierto, para consola está la función gets, pero gcc me da un aviso
de que es peligrosa y no debería usarla ¿ Alguien sabe por qué es esto ?
Post by Jose Luis Hernandez Toribio
Otro problema. Cuando introduzco una opción de un menú (con scanf) y le doy a
Enter
Post by garlito
Post by Jose Luis Hernandez Toribio
cuando va a otra pantalla y allí espero la introducción de otra opción, es como
que
Post by garlito
Post by Jose Luis Hernandez Toribio
coge ese Enter anterior como introducido y aparece el mensaje de error que tengo
para que vuelva a introducir otra vez. Es decir, es como que guarda los retornos
de
Post by garlito
Post by Jose Luis Hernandez Toribio
carro anteriores lo cual hace que se produzcan mensajes de error en pantallas
siguientes cuando no se ha introducido aún nada. He probado con getc y nada.
He probado con setbuf(stdin, NULL) y nada.
Me he encontrado con el mismo problema, pero esto creo que es por la
entrada con buffer de UNIX, pasa igual con otros lenguajes. Lo que he
hecho es una función para limpiar el buffer. Si el último carácter leído
NO es un salto de línea, y no me interesa el resto del buffer, entonces
void limpiar_entrada(void)
{
char c;
do
{
c = getchar();
} while (c != '\n');
}
Salu2
--


___________________________

José Luis Hernández Toribio
___________________________
Jose Luis Hernandez Toribio
2004-05-28 10:28:18 UTC
Permalink
Hola,

gracias por vuestras respuestas.

Ya miré la sintaxis de scanf y ofrece más posibilidades de las que pensaba. También
hay que decir que la ayuda de las páginas man en linux es algo ambigua o escasa,
¿alguien sabe de un buen manual de C en la red? Yo tengo varios, pero todos están
cortados por el mismo patrón y no se adentran en todo lo que hay.

Me quedo con la solución de scanf("%c%*c",&codigo), entendida, y también la valía de
los corchetes, estilo a flex.

No he llegado al nivel de controlar que donde sólo se introduzca un número detecte
si mete una letra, y el resultado al hacer eso es que el resto de campos no deja
introducirlos y los mete a cero digamos. Así como al usar fgets, si te pasas de la
longitud pues ya se descontrola todo.
Imagino que para controlar hasta ese nivel los datos que introduces habrá que ir
leyendo tecla a tecla e ir comprobando si son correctas para el campo concreto en
que se esté y finalmente pasarlo a la variable final, ¿cierto? ¿así es cómo se haría
en C?


Un saludo,
Post by BitterB
Post by Jose Luis Hernandez Toribio
Hola,
gracias por contestar. Creo que vas a tener razón con lo de que el fgets
sí lo hace bien, pero aún no lo he podido comprobar porque arrastro el
problema de los retornos de carro y me ha impedido probarlo.
Personalmente para leer cadenas yo prefiero fgets, pero lo puedes hacer
tambien con scanf sin ningun problema. Echale un vistazo a la sintaxis de
scanf y sobre todo lo referente a la especificacion de formato de los datos
de entrada.
La diferencia principal entre fgets y scanf es que fgets leera datos hasta
encontrar un caracter nueva linea (\n), pero leera tambien este caracter
transformandolo en el indicador de fin de cadena. Sin embargo scanf leera
datos hasta encontrar un separador, que por defecto sera un espacio en
blanco (en este saco tambien entran tabuladores y caracteres nueva linea) y
este caracter NO lo lee, lo deja en el buffer. Scanf funciona asi
independientemente de que los datos de entrada sean enteros, caracteres o
cadenas.
Teniendo esto en cuenta, para leer una cadena que este formada por varias
palabras (separadas por espacios en blanco) no se puede hacer scanf("%s",
cadena) porque solo leera la primera palabra, sin embargo si que podrias
hacer algo como scanf("%[^\n]", cadena) esto seria algo asi como "lee todo
lo que te encuentres hasta llegar a un caracter nueva linea", y debes de
recordar que el caracter nueva linea se quedara en el buffer por lo que
deberias limpiarlo o recogerlo de alguna forma.
Post by Jose Luis Hernandez Toribio
Una duda que tengo con la función que muestras es en qué momento la
utilizas. Si yo por ejemplo, acabo de dar de alta un artículo y le doy el
código 9 y meto Enter para aceptar, ya coge ese Enter y me lo mete en la
descripción, por tanto yo no puedo meter nada ahí, me pasa al siguiente
campo.
scanf("%i", &codigo) Por lo que segun te he dicho mas arriba sobre el
funcionamiento de scanf lo que haces es leer el codigo del articulo y dejar
en el buffer el caracter nueva linea del Enter, de esta forma cuando vas a
leer la descripcion del articulo lo que haces es coger este caracter nueva
linea que queda en el buffer. Para solucionarlo podrias hacer algo asi al
leer el codigo del articulo: scanf("%i%*c", &codigo) Pruebalo y ya me
contaras que tal te va, y si no te enteras de lo que significa "%i%*c" ya
sabes, a repasar la sintaxis de scanf.
Ah! una cosa mas, para leer cadenas con scanf y dejar el buffer limpio
tambien podrias hacer lo siguiente: scanf("%[\n]%*c", cadena) Esto leera la
cadena y eliminara el caracter nueva linea del buffer.
Tan solo hay que echarle imaginacion ;)
Saludos.
--
Vamos a crear una civilizacion de la mente en el ciberespacio. Que sea mas
humana y hermosa que el mundo que vuestros gobiernos han creado hasta
ahora.
--


___________________________

José Luis Hernández Toribio
___________________________

Loading...