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.
Si al ejecutar de damos como cadena de entrada el carácter 'A' obtenemos esta salida:
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:
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".
Ahora, para ver que queda en el buffer hay que modificar un poco el programa anterior.
Si le damos como cadena de entrada "ABCDEFGHI" da el siguiente resultado:
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:
Al pasarle la cadena ABCDEFGHIJKL al programa obtenemos:
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.
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 (c) [Seleccionar]
#include <stdio.h>
#include <ctype.h>
#define MAX_BUFF 5
void representar_char(int c) {
printf("%i", c);
if(isalnum(c))
printf(" -> \'%c\'", c);
else {
switch(c) {
case '\0':
printf(" -> \'\\0\'");
break;
case '\n':
printf(" -> \'\\n\'");
break;
}
}
}
int main() {
char mi_buffer[MAX_BUFF];
int i;
printf(">> ");
fgets(mi_buffer, 3, stdin);
for(i = 0; i < MAX_BUFF; ++i) {
printf("mi_buffer[%i] : ", i);
representar_char(mi_buffer[i]);
putchar('\n');
}
return 0;
}
Si al ejecutar de damos como cadena de entrada el carácter 'A' obtenemos esta salida:
Código [Seleccionar]
>> 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 [Seleccionar]
>> 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 [Seleccionar]
>> 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 (c) [Seleccionar]
#include <stdio.h>
#include <ctype.h>
#define MAX_BUFF 5
void representar_char(int c) {
printf("%i", c);
if(isalnum(c))
printf(" -> \'%c\'", c);
else {
switch(c) {
case '\0':
printf(" -> \'\\0\'");
break;
case '\n':
printf(" -> \'\\n\'");
break;
}
}
}
int main() {
char mi_buffer[MAX_BUFF];
int i;
char c;
printf(">> ");
fgets(mi_buffer, 3, stdin);
for(i = 0; i < MAX_BUFF; ++i) {
printf("mi_buffer[%i] : ", i);
representar_char(mi_buffer[i]);
putchar('\n');
}
while((c = getchar()) != '\n') {
printf("caracter en stdin : ");
representar_char(c);
putchar('\n');
}
printf("caracter en stdin : ");
representar_char(c);
putchar('\n');
return 0;
}
Si le damos como cadena de entrada "ABCDEFGHI" da el siguiente resultado:
Código [Seleccionar]
>> 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 (c) [Seleccionar]
#include <stdio.h>
#include <ctype.h>
#define MAX_BUFF 5
void representar_char(int c) {
printf("%i", c);
if(isalnum(c))
printf(" -> \'%c\'", c);
else {
switch(c) {
case '\0':
printf(" -> \'\\0\'");
break;
case '\n':
printf(" -> \'\\n\'");
break;
}
}
}
int main() {
char mi_buffer[MAX_BUFF];
int i;
char c;
printf(">> ");
fgets(mi_buffer, MAX_BUFF + 2, stdin);
/* Qué hay dentro de mi_buffer */
for(i = 0; i < MAX_BUFF; ++i) {
printf("mi_buffer[%i] : ", i);
representar_char(mi_buffer[i]);
putchar('\n');
}
/* Cuidado aquí, esta parte de la memoria está fuera de todo contro */
for(i = MAX_BUFF; i < MAX_BUFF + 2; ++i) {
printf("*** mi_buffer[%i] : ", i);
representar_char(mi_buffer[i]);
putchar('\n');
}
/* Qué hay en stdin */
while((c = getchar()) != '\n') {
printf("caracter en stdin : ");
representar_char(c);
putchar('\n');
}
printf("caracter en stdin : ");
representar_char(c);
putchar('\n');
return 0;
}
Al pasarle la cadena ABCDEFGHIJKL al programa obtenemos:
Código [Seleccionar]
>> 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.