[?] Error fgets (Solucionado)

Iniciado por MeCraniDOS, 19 Enero 2014, 14:56 PM

0 Miembros y 1 Visitante están viendo este tema.

MeCraniDOS

Hola, tengo un problema con fgets, estoy intentando separar un numero de 4 digitos, e introducir cada uno de ellos en una posicion del array  :silbar:

Para eso lo guardo en un array de caracteres y asi ya me guarda en cada posicion un numero, pero tal y como esta el codigo ahora solo guarda tres (lo he mirado con el debugger), cuando en teoria deberia guardar 4 (MAX)

Debería hacer esto:

Numero: 4578

Pos_1      Pos_2      Pos_3      Pos_4
  4             5             7            8

Pero hace esto:

Numero: 4578

Pos_1      Pos_2      Pos_3      Pos_4
 4             5             7            -48

Es decir, la ultima posicion del array la toma como 0, y al restar 48 (es lo mismo usar la funcion atoi), se queda en -48  :o

Código (cpp) [Seleccionar]
#include <stdio.h>

#define MAX 4
#define TONUM 48

int main()
{
char Cadena[MAX];
int Numero[MAX];

       printf("Introduce un numero de 4 digitos: ");
       fgets(Cadena, MAX, stdin);
       getchar();

       // Ahora convertimos la cadena a numerico

       for(int i=0;i<MAX;i++)
       {
           Numero[i] = Cadena[i] - TONUM;
           printf("%d", Numero[i]);
       }

       return 0;
}


No se donde puedes estar el error, porque seguro que es muy tonto  :rolleyes:  :rolleyes:

Saludos

(El código es un recorte del grande, pero esa es la parte que falla, asi que quizas no va bien porque me he dejado algo  ;D )
"La física es el sistema operativo del Universo"
     -- Steven R Garman

avesudra

#1
Hola MeCraniDOS mira esto:
Citar
Código (cpp) [Seleccionar]
char * fgets ( char * str, int num, FILE * stream );

Get string from stream
Reads characters from stream and stores them as a C string into str until (num-1) characters have been read or either a newline or the end-of-file is reached, whichever happens first.
Fuente http://www.cplusplus.com/reference/cstdio/fgets/
Es decir que fgets por definición lee carácteres del stream y los almacena en str hasta un número de (num-1) carácteres, así que para arreglar tu codigo, o igualas MAX a 5 o pones MAX+1 en fgets como te he puesto en tu código:
Código (cpp) [Seleccionar]
   #include <stdio.h>
   
   #define MAX 4
   #define TONUM 48
   
   int main()
   {
   char Cadena[MAX];
   int Numero[MAX];
   
          printf("Introduce un numero de 4 digitos: ");
          fgets(Cadena, MAX+1, stdin);
          getchar();
   
          // Ahora convertimos la cadena a numerico
   
          for(int i=0;i<MAX;i++)
          {
              Numero[i] = Cadena[i] - TONUM;
              printf("%d", Numero[i]);
          }
   
          return 0;
   }

¡Un saludo!
Regístrate en

MeCraniDOS

Cita de: avesudra en 19 Enero 2014, 15:30 PM
Hola MeCraniDOS mira esto:Es decir que fgets por definición lee carácteres del stream y los almacena en str hasta un número de (num-1) carácteres

Eso es lo que habia hecho, poner (MAX + 1), pero no sabia el porque con 5 cogia 4, con 4 cogia 3, etc

Vale, pues muchas gracias ;-)

Saludos
"La física es el sistema operativo del Universo"
     -- Steven R Garman

amchacon

#3
Cita de: MeCraniDOS en 19 Enero 2014, 15:41 PMEso es lo que habia hecho, poner (MAX + 1), pero no sabia el porque con 5 cogia 4, con 4 cogia 3, etc
Pues esa no era la solución xD.

El código original funciona perfectamente, lo que pasa esque el último elemento es el caracter nulo. Por eso te sale -48.

Si pones en el fgets un (MAX+1), lo que pasará esque pondrá el caracter nulo FUERA de la cadena, modificar memoria que no te toca no es nada bueno nunca. Te funciona porque la cadena es la última variable que habías reservado de modo que solo estás modificando espacio vacio, si no fuera así estarías modificando el contenido de otra variable xD. Y si haces eso con memoria dinámica tu progama directamente abortará.

La solución es poner MAX = 5, también cambiara el for por:
Código (cpp) [Seleccionar]
for(int i=0;Cadena[i] != '\0';i++)
{
   Numero[i] = Cadena[i] - TONUM;
   printf("%d", Numero[i]);
}


De esa forma leerá hasta que encuentre el caracter nulo, lo que te permitirá meter cadenas de 1,2,3,4 caracteres. Tú código actual solo permite cadenas de 4 caracteres (si le metes 3, te saldrán un dato "extraño".
Por favor, no me manden MP con dudas. Usen el foro, gracias.

¡Visita mi programa estrella!

Rar File Missing: Esteganografía en un Rar

MeCraniDOS

Cita de: amchacon en 19 Enero 2014, 15:52 PM
Pues esa no era la solución xD.

El código original funciona perfectamente, lo que pasa esque el último elemento es el caracter nulo. Por eso te sale -48.

En un principio habia pensado lo del caracter nulo, pero al pasarlo por el debugger tampoco me ponia el '\0', asi que lo he descartado  :-[

De todas formas ya he modificado un par de cosas y funciona bien  :laugh:

Gracias  ;-)
"La física es el sistema operativo del Universo"
     -- Steven R Garman

amchacon

Cita de: MeCraniDOS en 19 Enero 2014, 16:53 PMEn un principio habia pensado lo del caracter nulo, pero al pasarlo por el debugger tampoco me ponia el '\0', asi que lo he descartado
'\0' es solo un simbolo para ti, el compilador lo traduce como un 0:
Código (cpp) [Seleccionar]
for(int i=0;Cadena[i] != 0;i++)
Por favor, no me manden MP con dudas. Usen el foro, gracias.

¡Visita mi programa estrella!

Rar File Missing: Esteganografía en un Rar

leosansan

Cita de: amchacon en 19 Enero 2014, 15:52 PM

La solución es poner MAX = 5, también cambiara el for por:
Código (cpp) [Seleccionar]
for(int i=0;Cadena[i] != '\0';i++)
{
   Numero[i] = Cadena[i] - TONUM;
   printf("%d", Numero[i]);
}




De esa forma leerá hasta que encuentre el caracter nulo, lo que te permitirá meter cadenas de 1,2,3,4 caracteres. Tú código actual solo permite cadenas de 4 caracteres (si le metes 3, te saldrán un dato "extraño".


La solución que aporta amchacon tiene un "pero", el caracter de fin de línea que introduce fgets al final de la cadena que podría tener efectos indeseables en el resto del código.

He aquí una salida con "repetición" para ver el efecto indeseado de ese caracter:


Código (cpp) [Seleccionar]

#include <stdio.h>
#define MAX 5
#define TONUM 48

int main()
{
char Cadena[MAX]={""},come_buffer[100];
int i,ch,Numero[MAX-1];

  while (1)
  {
    printf("\nIntroduce un numero de 4 digitos: \n");
    fgets(Cadena, MAX, stdin);
    // Ahora convertimos la cadena a numerico

    for(i=0;Cadena[i];i++)
    {
        Numero[i] = Cadena[i] - TONUM;
        printf("%d", Numero[i]);
    }//while((ch = getchar()) != '\n');
  }
  return 0;
}


Citar

Introduce un numero de 4 digitos:
1234
1234
Introduce un numero de 4 digitos:<==de forma automática "salta" la introducción a mano
-38
Introduce un numero de 4 digitos:
12345
1234
Introduce un numero de 4 digitos:<==de forma automática "salta" la introducción a mano y devuelve lo que quedaba en el buffer, el 5, acompañado además
5-38
Introduce un numero de 4 digitos:<==si es menor que 4 devuelve el número "acompañado"
12
12-38
Introduce un numero de 4 digitos:
5432
5432
Introduce un numero de 4 digitos:<==de forma automática "salta" la introducción a mano
-38
Introduce un numero de 4 digitos:<==si es menor que 4 devuelve el número "acompañado"
321
321-38
Introduce un numero de 4 digitos:
123456
1234
Introduce un numero de 4 digitos:<==salto automático y
56-38<==lo que queda en el buffer "acompañado"

Una forma de evitar ambas cosas, el caracter extraño y tener que limpiar el buffer, es sobredimensionar de entrada el array Cadena y ya luego nos ocupamos de darle el tamaño que queramos, 5 en este caso.

Con esta idea, ésta es la salida:


Citar

Introduce un numero de 4 digitos:
123
Numero=123      Cadena=123
Introduce un numero de 4 digitos:
1234567
Numero=1234     Cadena=1234
Introduce un numero de 4 digitos:
32
Numero=32       Cadena=32
Introduce un numero de 4 digitos:
32564
Numero=3256     Cadena=3256
Introduce un numero de 4 digitos:
3214
Numero=3214     Cadena=3214
Introduce un numero de 4 digitos:
1
Numero=1        Cadena=1

Código (cpp) [Seleccionar]

#include <stdio.h>
#define MAX 10
#define N 5
#define TONUM 48

int main()
{
char Cadena[MAX]={""},come_buffer[100];
int i,ch,Numero[N];

  while (1)
  {
    printf("\nIntroduce un numero de 4 digitos: \n");
    fgets(Cadena, MAX, stdin);
    if (strlen(Cadena)<MAX)
      Cadena[strlen(Cadena)-1] = '\0';
    Cadena[N-1] = '\0';
      // Ahora convertimos la cadena a numerico
    printf("Numero=");
    fflush(stdout);
    for(i=0;Cadena[i];i++)
    {
        Numero[i] = Cadena[i] - TONUM;
        printf("%d", Numero[i]);
    }
    printf("\tCadena=%s", Cadena);
  }
  return 0;
}


Es sólo una idea, ¡¡¡Ehhhh!!!. Admito con gusto otras sugerencias más cualificadas que la mía. ;) ;) ;)

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



amchacon

#7
Vaya pues no había caído en eso :-X. Muy buen ojo Leo.

Tú solución no funciona adecuadamente si le metes 9 caracteres o más. El buffer de escritura es una fulana de cuidado.

La solución que se me ocurre es leerlo caracter a caracter:
Código (cpp) [Seleccionar]
#include <stdio.h>
#define MAX 5
#define TONUM 48

int main()
{
   char Cadena[MAX+1]= {""};
   int i,Numero;
   char ch;

   while (1)
   {
       printf("\nIntroduce un numero de 4 digitos: \n");

       i = 0;

       //ch = getchar();

       while ((ch = getchar()) != '\n')
       {
           if (i < MAX)
               Cadena[i++] = ch;
       }

       Cadena[i] = 0;

       printf("Cadena = %s \t Numero = ",Cadena);

       // Ahora convertimos la cadena a numerico

       for(i=0; Cadena[i]; i++)
       {
           Numero = Cadena[i] - TONUM;
           printf("%d", Numero);
       }

       printf("\n");
   }
   return 0;
}
Por favor, no me manden MP con dudas. Usen el foro, gracias.

¡Visita mi programa estrella!

Rar File Missing: Esteganografía en un Rar

leosansan

Cita de: amchacon en 19 Enero 2014, 23:15 PM
Vaya pues no había caído en eso :-X. Muy buen ojo Leo.

Tú solución no funciona adecuadamente si le metes 9 caracteres o más. El buffer de escritura es una fulana de cuidado.

La solución que se me ocurre es leerlo caracter a caracter:


Excelente opción. ;-) ;-) ;-

Y lo de los nueve caracteres es por el tamaño que le dí a MAX, Si lo pongo mayor más "traga". Pero no es plan, claro.

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




amchacon

#9
Cita de: leosansan en 20 Enero 2014, 11:17 AMY lo de los nueve caracteres es por el tamaño que le dí a MAX, Si lo pongo mayor más "traga". Pero no es plan, claro.
No es eso, sino que se salta un caso. Y si le pongo aún más se salta más casos.
Por favor, no me manden MP con dudas. Usen el foro, gracias.

¡Visita mi programa estrella!

Rar File Missing: Esteganografía en un Rar