elhacker.net cabecera Bienvenido(a), Visitante. Por favor Ingresar o Registrarse
¿Perdiste tu email de activación?.

 

 


Tema destacado: ¿Eres nuevo? ¿Tienes dudas acerca del funcionamiento de la comunidad? Lee las Reglas Generales


+  Foro de elhacker.net
|-+  Programación
| |-+  Programación C/C++ (Moderadores: Eternal Idol, Littlehorse, K-YreX)
| | |-+  [C] Limpiando la stdin correctamente...
0 Usuarios y 1 Visitante están viendo este tema.
Páginas: [1] Ir Abajo Respuesta Imprimir
Autor Tema: [C] Limpiando la stdin correctamente...  (Leído 5,246 veces)
zShackra

Desconectado Desconectado

Mensajes: 59


Ver Perfil WWW
[C] Limpiando la stdin correctamente...
« en: 12 Noviembre 2014, 04:12 am »

Hola, he creado una función personalizada de la función getline() que aparece en el libro de K&R (en su primer capítulo)... quisiera me comentaran su comportamiento bajo sistemas Un*x:

Código
  1. int getLine(char buffer[], int max)
  2. {
  3. int c = EOF, i;
  4.  
  5. if (!max)
  6. return 0;
  7.  
  8. for (i = 0; i < max - 1 && (c = getchar()) != EOF && c != '\n'; ++i)
  9. buffer[i] = c;
  10.  
  11. buffer[i] = '\0';
  12.  
  13. while (c != '\n' && c != EOF)
  14. c = getchar();
  15.  
  16. return (i);
  17. }

Para quien no la comprenda, aunque es bastante simple, simplemente se leen hasta max - 1 caracteres y se asignan a buffer[], la diferencia con fgets() es que dicha función nos puede dejar basura en la stdin si el usuario introduce una cadena más larga de lo esperado y así, al momento de intentar leer con cualquier otra función desde la stdin, vamos a leer los caracteres que sobraron de la lectura anterior.

Lógicamente se pueden limpiar con una macro:

Código
  1. #define stdinClr() int c; while ((c = getchar()) != '\n' && c != EOF);

Tal y como lo hago en getLine(), pero si usáramos siempre fgets() + stdinClr(), en caso que el usuario no ingresara más caracteres de lo esperado, fgets() realizaría su trabajo correctamente y el programa esperaría la entrada de un salto de línea o fin de archivo... lo cual es un comportamiento indeseado.

Por lo que la función getLine() considero es la más apropiada para obtener una cadena de n - 1 caracteres y así trabajar con la misma de forma más segura... con la stdin, claramente.

Ergo, quisiera saber si funciona en otros sistemas fuera de la familia NT. Si alguien tiene la amabilidad... lo que deseo es deshacerme de fgets() + stdClr() para con la stdin y hacerlo de forma portable.


« Última modificación: 12 Noviembre 2014, 20:54 pm por zShackra » En línea

eferion


Desconectado Desconectado

Mensajes: 1.248


Ver Perfil
Re: [C] Limpiando la stdin correctamente...
« Respuesta #1 en: 12 Noviembre 2014, 09:03 am »

Hola, he creado una función personalizada de la función getline() que aparece en el libro de K&R (en su primer capítulo)... quisiera me comentaran su comportamiento bajo sistemas Un*x:

En eso no te puedo ayudar demasiado, mi entorno de trabajo actual, para bien o para mal, es Windows.

Lógicamente se pueden limpiar con una macro:

Las macros que inyectan código hay que manejarlas con cuidado... en este caso, si tienes otra variable que se llama "c" dentro de la función en la que incluyas esta macro vas a tener problemas de compilación.

A mi modo de ver es mejor crear una función específica... pero no deja de ser mi opinión.


En línea

daryo


Desconectado Desconectado

Mensajes: 1.070



Ver Perfil WWW
Re: [C] Limpiando la stdin correctamente...
« Respuesta #2 en: 12 Noviembre 2014, 14:45 pm »

funciona en linux.Solo un pequeñp cambio:
Código
  1. buffer[i++] = '\0';

y no le vi utilidad a esto:
Código
  1. if (c != '\n' && c != EOF)
  2. while ((c = getchar()) != '\n' && c != EOF);

lo quite y funciona igual sin problemas de buffer(al menos en linux compilador gcc ) xD
« Última modificación: 12 Noviembre 2014, 16:31 pm por daryo » En línea

buenas
vangodp


Desconectado Desconectado

Mensajes: 455



Ver Perfil
Re: [C] Limpiando la stdin correctamente...
« Respuesta #3 en: 12 Noviembre 2014, 15:39 pm »

Y que te parece mi scanf cañero que te ajora to lo anterior?
char cadena[100];
scanf ( "%99[^\n]%*c", cadena );

con esta criatura lees un string de maximo 99 chars, te mete el \0 al final, evita el molesto enter y también el tener que limpiar ningún buffer XDDD  :silbar:
A ver que opinan  ;-)
En línea

leosansan


Desconectado Desconectado

Mensajes: 1.314


Ver Perfil
Re: [C] Limpiando la stdin correctamente...
« Respuesta #4 en: 12 Noviembre 2014, 16:01 pm »

Y que te parece mi scanf cañero que te ajora to lo anterior?
char cadena[100];
scanf ( "%99[^\n]%*c", cadena );

con esta criatura lees un string de maximo 99 chars, te mete el \0 al final, evita el molesto enter y también el tener que limpiar ningún buffer XDDD  :silbar:
A ver que opinan  ;-)

¿Y si metes 120 caracteres dónde crees que se van a situar los restantes a 99?. ¡¡¡¡ EN EL BUFFER ¡¡¡. Por lo tanto, en ese caso queda por limpiarlo si te excedes en el tamaño.  ;)

Es más, en ese caso el "%*c" se comería el primer caracter en exceso, quedando en el buffer los restantes y "acompañados" del "\n" con lo que si hay otro scanf posterior se lo saltaría.

¡¡¡¡ Saluditos! ..... !!!!


« Última modificación: 12 Noviembre 2014, 16:11 pm por leosansan » En línea

eferion


Desconectado Desconectado

Mensajes: 1.248


Ver Perfil
Re: [C] Limpiando la stdin correctamente...
« Respuesta #5 en: 12 Noviembre 2014, 16:15 pm »

mi opinión es que la librería estándar podría estar un poco más completa en este apartado.
En línea

daryo


Desconectado Desconectado

Mensajes: 1.070



Ver Perfil WWW
Re: [C] Limpiando la stdin correctamente...
« Respuesta #6 en: 12 Noviembre 2014, 16:19 pm »

mi opinión es que la librería estándar podría estar un poco más completa en este apartado.

si :/ siempre he dicho que c/c++ en cuanto a manejo de cadenas tiene herramientas demasiado basicas pero cuando lo digo los amantes de c/c++ sacan sus garras xD
En línea

buenas
eferion


Desconectado Desconectado

Mensajes: 1.248


Ver Perfil
Re: [C] Limpiando la stdin correctamente...
« Respuesta #7 en: 12 Noviembre 2014, 16:31 pm »

si :/ siempre he dicho que c/c++ en cuanto a manejo de cadenas tiene herramientas demasiado basicas pero cuando lo digo los amantes de c/c++ sacan sus garras xD

A mi me gusta bastante tanto C como C++, opino que son muy potentes y versátiles, pero me chocan cosas como...

* Que la librería estándar de C de un soporte tan pobre a algo tan básico como la consola.
* Que existan hasta tres formas diferentes de sobrecargar los mismos operadores.
* Que a estas alturas de la vida, C++ no admita templates abstractos
* Que no se vaya limitando el uso de las macros en pro de mejores herramientas.

Cada punto tiene su por qué, ya me conozco los motivos y no hace falta que me las recordéis... solo digo que el mundo cambia y los lenguajes deberían intentar hacerlo al mismo ritmo... bien es cierto que a C++ se le está dando últimamente cierto impulso con los estándares C++11 y C++14... pero al final, como siempre, la compatibilidad acaba siendo un lastre importante... es un punto controvertido, lo se, pero mi opinión es que se deberían ir dejando de lado ciertas características en vez de únicamente añadir nuevos elementos al lenguaje.
En línea

rir3760


Desconectado Desconectado

Mensajes: 1.639


Ver Perfil
Re: [C] Limpiando la stdin correctamente...
« Respuesta #8 en: 12 Noviembre 2014, 16:52 pm »

he creado una función personalizada de la función getline() que aparece en el libro de K&R (en su primer capítulo)
Algunos comentarios:

* Quien llama a tu función es responsable de pasar argumentos validos, si revienta es su problema. Por ello en mi opinión deberías quitar la validación de los argumentos y si piensas dejarla debes retornar 0 (NULL es usualmente un puntero de tipo "void *").

* En caso de una linea vacía, error y fin de archivo tu función retorna cero, para discriminar los casos habrá que llamar a feof y ferror (mejor deja el avance de linea y ya tienes un indicador).

* El ultimo if + while se puede sustituir por un bucle while con la lectura del siguiente carácter como su cuerpo.

Un saludo
En línea

C retains the basic philosophy that programmers know what they are doing; it only requires that they state their intentions explicitly.
--
Kernighan & Ritchie, The C programming language
zShackra

Desconectado Desconectado

Mensajes: 59


Ver Perfil WWW
Re: [C] Limpiando la stdin correctamente...
« Respuesta #9 en: 12 Noviembre 2014, 20:44 pm »

Las macros que inyectan código hay que manejarlas con cuidado... en este caso, si tienes otra variable que se llama "c" dentro de la función en la que incluyas esta macro vas a tener problemas de compilación.

A mi modo de ver es mejor crear una función específica... pero no deja de ser mi opinión.

Sí, quizá sea mejor crear una función...

funciona en linux.Solo un pequeñp cambio:
Código
  1. buffer[i++] = '\0';

Gracias por confirmarme lo de GNU/Linux, no veo utilidad en aumentar i para devolver la cantidad de caracteres leídos... estaríamos devolviendo el tamaño completo del arreglo, pero bien especifiqué antes que:

(...) simplemente se leen hasta max - 1 caracteres y se asignan a buffer[] (...)

Es decir, la función devuelve la cantidad de caracteres leídos, no toma en cuenta el carácter nulo.

Algunos comentarios:

* Quien llama a tu función es responsable de pasar argumentos validos, si revienta es su problema. Por ello en mi opinión deberías quitar la validación de los argumentos y si piensas dejarla debes retornar 0 (NULL es usualmente un puntero de tipo "void *").

* En caso de una linea vacía, error y fin de archivo tu función retorna cero, para discriminar los casos habrá que llamar a feof y ferror (mejor deja el avance de linea y ya tienes un indicador).

* El ultimo if + while se puede sustituir por un bucle while con la lectura del siguiente carácter como su cuerpo.

Un saludo

Cuando dices que puede reventar, específicamente ¿a qué te refieres?. He modificado el código un poco para tratar de cubrir los errores que hasta ahora puedo corregir (voy por el capítulo 2 del libro de K&R, por eso no he usado correctamente los argumentos de las funciones ni he tocado los punteros directamente).
« Última modificación: 23 Noviembre 2014, 07:14 am por zShackra » En línea

Páginas: [1] Ir Arriba Respuesta Imprimir 

Ir a:  

Mensajes similares
Asunto Iniciado por Respuestas Vistas Último mensaje
Sber si hay datos en stdin ?
Programación C/C++
lDanny 6 3,395 Último mensaje 25 Mayo 2010, 11:39 am
por lDanny
duda sockets no bloqueantes+stdin
Programación C/C++
nosoqui 1 2,826 Último mensaje 5 Septiembre 2011, 14:24 pm
por nosoqui
Limpiando el PC a lo bestia...XXD!
Hardware
nichihack 3 3,728 Último mensaje 15 Febrero 2012, 17:35 pm
por HdM
El bendito stdin...
Programación C/C++
zShackra 4 3,152 Último mensaje 26 Noviembre 2014, 09:32 am
por zShackra
Definición de stdin en C
Programación C/C++
fafafa01 8 4,825 Último mensaje 10 Septiembre 2017, 12:39 pm
por ivancea96
WAP2 - Aviso Legal - Powered by SMF 1.1.21 | SMF © 2006-2008, Simple Machines