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

 

 


Tema destacado: Sigue las noticias más importantes de seguridad informática en el Twitter! de elhacker.NET


+  Foro de elhacker.net
|-+  Programación
| |-+  Programación C/C++ (Moderadores: Eternal Idol, Littlehorse, K-YreX)
| | |-+  Comportamiento de la función fgets(lenguaje C).
0 Usuarios y 1 Visitante están viendo este tema.
Páginas: [1] Ir Abajo Respuesta Imprimir
Autor Tema: Comportamiento de la función fgets(lenguaje C).  (Leído 4,940 veces)
NOB2014


Desconectado Desconectado

Mensajes: 366



Ver Perfil
Comportamiento de la función fgets(lenguaje C).
« en: 23 Marzo 2016, 05:02 am »

Hola.

Código
  1. fgets( word[i], MAX_COL , stdin );
  2.  
  3. if((p=strchr(word[i], '\n'))){
  4. *p='\0';
  5. }
  6. else{
  7. while((ch = getchar()) !='\n' && ch!=EOF);
  8. word[i][MAX_COL] = '\0';
  9. }


En este trozo de código está mi gran duda, según lo que tengo leído es que si ingreso menos caracteres que  MAX_COL fgets los guarda desde el buffer de teclado en la variable indicada, en este caso word y también el carácter de nueva línea (\n) que se produce al apretar < Enter >, la primera duda, ¿es estrictamente necesario remplazar el carácter \n por \0? -
En el caso de ingresar más caracteres del establecido por MAX_COL fgets lee  MAX_COL – 1 y en la última casilla de memoria asignada a MAX_COL copia el carácter \n, de ser esto cierto la otra duda es:  ¿la sentencia else no se ejecuta nunca en este caso, o estoy equivocado?

Es todo y desde ya muchas gracias por el tiempo que le dediquen al tema,-

Saludos.
Daniel



« Última modificación: 24 Marzo 2016, 14:39 pm por NOB2014 » En línea

abraza las cosas y personas malas como si fueran tu mas preciada joya,Son tus mas grandes maestros de paciencia sabiduría y amor y cuando lo abrazas dejan de causar dolor.-
MAFUS


Desconectado Desconectado

Mensajes: 1.603



Ver Perfil
Re: Duda con la función fgets (lenguaje C).
« Respuesta #1 en: 23 Marzo 2016, 13:26 pm »

Sobre la 1ª pregunta: Cuándo guardas un dato, eso es un nombre, una dirección, etc. éstos no tienen implícitos cambios de línea Es de buena práctica separar los datos de su presentación: el dato es la cadena, la presentación dicta si debe haber un salto de línea o no. Por consiguiente sí, es bueno quitar el salto de línea.

Sobre la 2ª pregunta: fgets copia los N primeros caracteres teniendo en cuenta siempre que el último carácter de la cadena destino será '\0' así que en verdad se copian N-1 caracteres; de esta forma fgets se asegura que en el destino hay una cadena con su final. Los caracteres que no fueron copiados se quedan en el búffer del teclado.


« Última modificación: 23 Marzo 2016, 23:01 pm por MAFUS » En línea

NOB2014


Desconectado Desconectado

Mensajes: 366



Ver Perfil
Re: Duda con la función fgets (lenguaje C).
« Respuesta #2 en: 24 Marzo 2016, 02:47 am »

Hola, MAFUS.
Ahora si me que más claro, por lo menos la primer pregunta, en cuanto a la segunda no logro interpretarte demasiado, no obstante, hice mis propias pruebas y en la práctica pasa lo siguiente:
si por Ej. la cadena soporta 10 caracteres, si ingreso 9 o menos se ejecuta la línea que está a continuación del if, en cambio si ingreso 10 o más caracteres se ejecutan las líneas que estan a continuación del else, o sea en la práctica todo funciona correctamente, en la teoria no me queda claro lo siguiente:
De las dos formas (ingrece menos de 10 o ingrece mas de 9 ) el caracter \n va a estar siempre y como está escrito el programa nunca deberia ejecutarse la sentencia else.-
espero encontrar la explicación a esto.- 

Saludos.
Daniel
En línea

abraza las cosas y personas malas como si fueran tu mas preciada joya,Son tus mas grandes maestros de paciencia sabiduría y amor y cuando lo abrazas dejan de causar dolor.-
MAFUS


Desconectado Desconectado

Mensajes: 1.603



Ver Perfil
Re: Duda con la función fgets (lenguaje C).
« Respuesta #3 en: 24 Marzo 2016, 12:02 pm »

Te voy a mostrar una serie de programa de pruebas que te mostrarán el funcionamiento de fgets y lo que ocurre con el buffer stdin.

Es una buena idea realizar estos programas cuándo estudias programación para saber que ocurre en cada situación.

Este primero te enseñará qué copia desde stdin a tu buffer cuando le das a fgets un tamaño inferior al tamaño de tu buffer. En este caso tenemos un buffer de 5 elementos y fgets solo puede copiar 3.

Código
  1. #include <stdio.h>
  2. #include <ctype.h>
  3.  
  4. #define MAX_BUFF 5
  5.  
  6. void representar_char(int c) {
  7.    printf("%i", c);
  8.    if(isalnum(c))
  9.        printf(" -> \'%c\'", c);
  10.    else {
  11.        switch(c) {
  12.            case '\0':
  13.                printf("  -> \'\\0\'");
  14.                break;
  15.            case '\n':
  16.                printf(" -> \'\\n\'");
  17.                break;
  18.        }
  19.    }
  20. }
  21.  
  22. int main() {
  23.    char mi_buffer[MAX_BUFF];
  24.    int i;
  25.    printf(">> ");
  26.    fgets(mi_buffer, 3, stdin);
  27.    for(i = 0; i < MAX_BUFF; ++i) {
  28.        printf("mi_buffer[%i] : ", i);
  29.        representar_char(mi_buffer[i]);
  30.        putchar('\n');
  31.    }
  32.  
  33.    return 0;
  34. }
  35.  

Si al ejecutar de damos como cadena de entrada el carácter 'A' obtenemos esta salida:

Código:
>> A
mi_buffer[0] : 65 -> 'A'
mi_buffer[1] : 10 -> '\n'
mi_buffer[2] : 0  -> '\0'
mi_buffer[3] : -86
mi_buffer[4] : -2

Vemos que en primer lugar se guarda el carácter 'a', seguidamente el carácter de nueva línea '\n' y finalmente el caracter nulo '\0'. A partir del cuarto elemento, mi_buffer[3], lo que hay es basura.

Ahora, si le das como entrada la cadena "AB" verás el siguiente resultado:

Código:
>> AB
mi_buffer[0] : 65 -> 'A'
mi_buffer[1] : 66 -> 'B'
mi_buffer[2] : 0  -> '\0'
mi_buffer[3] : -80
mi_buffer[4] : -3

Como puedes ver no se ha guardado en el mi_buffer el carácter de nueva línea, que sigue existiendo en el buffer stdin, como veremos más adelante. Para corroborar que el último carácter a guardar siempre será un '\0' puedes repetir el programa esta vez con la cadena "ABC".

Código:
>> ABC
mi_buffer[0] : 65 -> 'A'
mi_buffer[1] : 66 -> 'B'
mi_buffer[2] : 0  -> '\0'
mi_buffer[3] : -13
mi_buffer[4] : -2

Ahora, para ver que queda en el buffer hay que modificar un poco el programa anterior.
Código
  1. #include <stdio.h>
  2. #include <ctype.h>
  3.  
  4. #define MAX_BUFF 5
  5.  
  6. void representar_char(int c) {
  7.    printf("%i", c);
  8.    if(isalnum(c))
  9.        printf(" -> \'%c\'", c);
  10.    else {
  11.        switch(c) {
  12.            case '\0':
  13.                printf("  -> \'\\0\'");
  14.                break;
  15.            case '\n':
  16.                printf(" -> \'\\n\'");
  17.                break;
  18.        }
  19.    }
  20. }
  21.  
  22. int main() {
  23.    char mi_buffer[MAX_BUFF];
  24.    int i;
  25.    char c;
  26.    printf(">> ");
  27.    fgets(mi_buffer, 3, stdin);
  28.    for(i = 0; i < MAX_BUFF; ++i) {
  29.        printf("mi_buffer[%i] : ", i);
  30.        representar_char(mi_buffer[i]);
  31.        putchar('\n');
  32.    }
  33.    while((c = getchar()) != '\n') {
  34.        printf("caracter en stdin : ");
  35.        representar_char(c);
  36.        putchar('\n');
  37.    }
  38.    printf("caracter en stdin : ");
  39.    representar_char(c);
  40.    putchar('\n');
  41.    return 0;
  42. }
  43.  

Si le damos como cadena de entrada "ABCDEFGHI" da el siguiente resultado:
Código:
>> ABCDEFGHI 
mi_buffer[0] : 65 -> 'A'
mi_buffer[1] : 66 -> 'B'
mi_buffer[2] : 0  -> '\0'
mi_buffer[3] : -79
mi_buffer[4] : -1
caracter en stdin : 67 -> 'C'
caracter en stdin : 68 -> 'D'
caracter en stdin : 69 -> 'E'
caracter en stdin : 70 -> 'F'
caracter en stdin : 71 -> 'G'
caracter en stdin : 72 -> 'H'
caracter en stdin : 73 -> 'I'
caracter en stdin : 10 -> '\n'

mi_buffer sigue recibiendo tantos caracteres como le hemos dicho a fgets, ver que uno de ellos es el carácter '\0' pues debe crear una cadena, lo demás se encuentra esperando en el buffer stdin.

Por último hay que ver que pasa si a fgets se le pasa un tamaño a copiar mayor que el tamaño de buffer de destino y la cadena a copiar también es mayor que el destino. Para ello modificamos de nuevo el programa:

Código
  1. #include <stdio.h>
  2. #include <ctype.h>
  3.  
  4. #define MAX_BUFF 5
  5.  
  6. void representar_char(int c) {
  7.    printf("%i", c);
  8.    if(isalnum(c))
  9.        printf(" -> \'%c\'", c);
  10.    else {
  11.        switch(c) {
  12.            case '\0':
  13.                printf("  -> \'\\0\'");
  14.                break;
  15.            case '\n':
  16.                printf(" -> \'\\n\'");
  17.                break;
  18.        }
  19.    }
  20. }
  21.  
  22. int main() {
  23.    char mi_buffer[MAX_BUFF];
  24.    int i;
  25.    char c;
  26.    printf(">> ");
  27.    fgets(mi_buffer, MAX_BUFF + 2, stdin);
  28.  
  29.    /* Qué hay dentro de mi_buffer */
  30.    for(i = 0; i < MAX_BUFF; ++i) {
  31.        printf("mi_buffer[%i] : ", i);
  32.        representar_char(mi_buffer[i]);
  33.        putchar('\n');
  34.    }
  35.  
  36.    /* Cuidado aquí, esta parte de la memoria está fuera de todo contro */
  37.    for(i = MAX_BUFF; i < MAX_BUFF + 2; ++i) {
  38.        printf("*** mi_buffer[%i] : ", i);
  39.        representar_char(mi_buffer[i]);
  40.        putchar('\n');
  41.    }
  42.  
  43.    /* Qué hay en stdin */
  44.    while((c = getchar()) != '\n') {
  45.        printf("caracter en stdin : ");
  46.        representar_char(c);
  47.        putchar('\n');
  48.    }
  49.    printf("caracter en stdin : ");
  50.    representar_char(c);
  51.    putchar('\n');
  52.    return 0;
  53. }
  54.  

Al pasarle la cadena ABCDEFGHIJKL al programa obtenemos:

Código:
>> ABCDEFGHIJKL
mi_buffer[0] : 65 -> 'A'
mi_buffer[1] : 66 -> 'B'
mi_buffer[2] : 67 -> 'C'
mi_buffer[3] : 68 -> 'D'
mi_buffer[4] : 69 -> 'E'
*** mi_buffer[5] : 70 -> 'F'
*** mi_buffer[6] : 0  -> '\0'
caracter en stdin : 71 -> 'G'
caracter en stdin : 72 -> 'H'
caracter en stdin : 73 -> 'I'
caracter en stdin : 74 -> 'J'
caracter en stdin : 75 -> 'K'
caracter en stdin : 76 -> 'L'
caracter en stdin : 10 -> '\n'

Se puede ver que fgets sigue cumpliendo su trabajo, copia tantos caracteres como le hemos dicho, ha desbordado mi_buffer, pero trabaja como se espera de él. Los datos en marcados en *** están fuera de todo control y podrían darse otras situaciones como el cierre del programa, cuelgue del sistema, etc.
Para terminar se sigue viendo en en stdin está el resto de la cadena que no se ha copiado.
En línea

NOB2014


Desconectado Desconectado

Mensajes: 366



Ver Perfil
Re: Comportamiento de la función fgets(lenguaje C).
« Respuesta #4 en: 24 Marzo 2016, 23:01 pm »

Hola, MAFUS.
ahora sí que queda todo clarísimo ;-) ;-) ;-), gracias por el tiempo que le dedicaste y te debo una cerveza con maníes. -

Saludos.
Daniel

« Última modificación: 9 Abril 2016, 04:10 am por NOB2014 » En línea

abraza las cosas y personas malas como si fueran tu mas preciada joya,Son tus mas grandes maestros de paciencia sabiduría y amor y cuando lo abrazas dejan de causar dolor.-
Páginas: [1] Ir Arriba Respuesta Imprimir 

Ir a:  

Mensajes similares
Asunto Iniciado por Respuestas Vistas Último mensaje
funcion mostrar lista doble lenguaje c
Programación C/C++
spectrumni 2 3,883 Último mensaje 26 Enero 2012, 23:39 pm
por spectrumni
No me reconoce función fgets
Desarrollo Web
..:ALT3RD:.. 4 2,934 Último mensaje 23 Agosto 2013, 19:25 pm
por ..:ALT3RD:..
Programa se cierra al llamar a una funcion dentro de un do-while (lenguaje C)
Programación C/C++
polopo100 4 3,680 Último mensaje 15 Septiembre 2014, 20:43 pm
por eferion
Ayuda con la funcion fwrite en lenguaje c
Programación C/C++
maicol_962016 3 2,418 Último mensaje 19 Febrero 2016, 10:25 am
por fary
(Consulta) Funcion FgetS en arreglo bidemensional
Programación C/C++
palacio29 2 2,046 Último mensaje 29 Agosto 2016, 14:09 pm
por AlbertoBSD
WAP2 - Aviso Legal - Powered by SMF 1.1.21 | SMF © 2006-2008, Simple Machines