[ Foro de C ]

Problema con gets y scanf

28-Jun-2012 16:42
Rudi Merlos Carrion
3 Respuestas

El problema es que cuando se trabaja con cadenas tanto scanf como gets no me funcionan bien. ¿que estoy haciendo mal?. Aqui dejo un ejemplo (ejercicio 5.5.2.i), en el que me da problemas a partir de la linea 34 cuando intento capturar el nombre del artista y el titulo de la canción. El resultado es:
  Nombre del artista: Titulo de la canción: Duración en segundos: (aquí ya puedo introducir datos)

He encontrado una manera que es doblando la primera captura:
gets(info[i].artist)
gets(info[i].artist)

y así funciona bien pero solo la primera vez, a partir de la segunda canción, en artista tengo que darle dos veces a intro para pasar a titulo.

#include <stdio.h>
#include <string.h>

struct
{
   char artist[80], titulo[80];
   int duracion, size;
}info[100], aux[100];

main(){
   
  char c, txt[40];
  int i, j, n;
   
  printf("   \"MENÚ\"\n\n");
  printf("Pulse \"A\" para agregar una nueva canción\n");
  printf("Pulse \"T\" para mostrar todos los títulos\n");
  printf("pulse \"B\" para buscar\n");
  printf("Pulse \"S\" para salir\n");
   
  lazo: printf("\n\nIntroduzca una opción: ");
  c = getchar();
   
  switch (c){
  case 'a':
     lazo1: printf("\n\n¿Cuantas canciones va a guardar?  ");
     scanf("%d", &n);
     if (n>0 && n<=100){
        for (i=0; i<n; i++){
           printf("\n\n\tTrack No. %d", i+1);
                   
           printf("\nNombre del artista: ");
           gets(info[i].artist);
           printf("Titulo de la canción: ");
           gets(info[i].titulo);
                   
           sprintf(aux[i].titulo, "%s", info[i].titulo);
                   
           printf("Duración en segundos: ");
           scanf("%d", &info[i].duracion);
           printf("Tamaño en Kb: ");
           scanf("%d", &info[i].size);
           getchar();
        }  
        printf("\n\n\tSALIDA");
        for(i=0; i<n; i++){
           printf("\n\n\tTrack No. %d\n", i+1);
           printf("Título: %s", info[i].titulo);
           printf("\nArtista: %s", info[i].artist);
           printf("\nDuración: %d", info[i].duracion);
           printf("\nTamaño: %d", info[i].size);
        }
        goto lazo;
     }
     else
        printf("\nTeclee un n??mero entre el uno y el 100");
     goto lazo1;
           
  case 't':
     printf("\nLista de canciones:\n");
     for(i=0; i<n; i++){
        printf("%d - %s", i+1, info[i]);
        if (n == 0)
           printf("No se encontró ninguna canción");
     }
  getchar();
  goto lazo;
           
  case 'b':
     printf("\nBuscador: ");
     gets(txt);
           
     for (i=0, j=0; i<n; i++, j++){
        if (strstr(info[i].artist, txt) || strstr(info[i].titulo, txt) != NULL){
           printf("\nSe encontr?? coincidencia en Track No. %d\n", i+1);
           j--;
        }
     }
     if (i == j)
        printf("\nNo se encontr?? ninguna coincidencia");
  getchar();
  goto lazo;    
           
           
  default:
     printf("\n...ERROR!");
  goto lazo;
  }
   
getchar();
return 0;
}

No se si me he explicado bien pero gracias de todas formas.


29-Jun-2012 03:30
Pablo Rampa

Hola Rudi!

Tuve el mismo problema con "scanf" y "gets".
Te transcribo lo que el Profesor Nacho me dijo al respecto:

"Cuando lees un número y después un texto, en el teclado se introduce el número y se pulsa Intro, luego el texto y se vuelve a pulsar Intro. Si usas un "scanf("%d", ...", la variable numérica guardará el número... pero el Intro queda esperando en el buffer del teclado. Si lees un segundo número, no hay problema, porque se omite ese Intro, pero si lees una cadena, ese Intro es aceptable, porque representaría una cadena vacía.

Por eso, cuando lees primero un número y luego una cadena, tendrás que "absorber" el Intro. Una forma de hacerlo sería:

scanf("%d",...
getchar();
gets(...

En el caso del ejercicio 5.6.iii, el getchar no debe ir (conceptualmente) antes de leer el nombre, sino después de pedir la opción numérica.


 No uses "goto". Conduce a programas muy poco legibles, y es evitable en un 99% de los casos. Casi cualquier cosa que hagas con un "for" la podrás hacer también de forma más elegante y más legible con un "while" o un "do-while".

En muchos centros de estudios, el uso injustificado de "goto" supone un suspenso inmediato. Desde luego, si fueras mi alumno, lo sería.  ;-)" Fin de la cita.

En tu código anoté algunos comentarios. Pule más el programa,
porque además de los puntos comentados, parece que no corre satisfactoriamente:

#include <stdio.h>
#include <string.h>

struct
{
   char artist[80], titulo[80];
   int duracion, size;
}info[100], aux[100];

int main(){             /*  faltaba int. */
 
 char c, txt[40];
 int i, j, n;
 
 printf("  \"MENÚ\"\n\n");
 printf("Pulse \"A\" para agregar una nueva canción\n");  
/* "A" es diferente a 'a', etc.*/  
 printf("Pulse \"T\" para mostrar todos los títulos\n");
 printf("pulse \"B\" para buscar\n");
 printf("Pulse \"S\" para salir\n");
 
 lazo: printf("\n\nIntroduzca una opción: ");
 c = getchar();
 
 switch (c){
 case 'a':
     lazo1: printf("\n\n¿Cuantas canciones va a guardar?  ");  /* No usar goto. */
     scanf("%d", &n);
     getchar();            /* .....Para absorver el "intro". */
     if (n>0 && n<=100){
       for (i=0; i<n; i++){
           printf("\n\n\tTrack No. %d", i+1);
                 
           printf("\nNombre del artista: ");
           gets(info[i].artist);
           printf("Titulo de la canción: ");
           gets(info[i].titulo);
                 
           sprintf(aux[i].titulo, "%s", info[i].titulo);
                 
           printf("Duración en segundos: ");
           scanf("%d", &info[i].duracion);
           printf("Tamaño en Kb: ");
           scanf("%d", &info[i].size);
           getchar();      /* .....Para absorver el "intro". */
       }
       printf("\n\n\tSALIDA");
       for(i=0; i<n; i++){
           printf("\n\n\tTrack No. %d\n", i+1);
           printf("Título: %s", info[i].titulo);
           printf("\nArtista: %s", info[i].artist);
           printf("\nDuración: %d", info[i].duracion);
           printf("\nTamaño: %d", info[i].size);
       }
       goto lazo;
     }
     else
       printf("\nTeclee un n??mero entre el uno y el 100");
     goto lazo1;
         
 case 't':
     printf("\nLista de canciones:\n");
     for(i=0; i<n; i++){
       printf("%d - %s", i+1, info[i]);
       if (n == 0)
           printf("No se encontró ninguna canción");
     }
 getchar();
 goto lazo;
         
 case 'b':
     printf("\nBuscador: ");
     gets(txt);
         
     for (i=0, j=0; i<n; i++, j++){
       if (strstr(info[i].artist, txt) || strstr(info[i].titulo, txt) != NULL){
           printf("\nSe encontr?? coincidencia en Track No. %d\n", i+1);
           j--;
       }
     }
     if (i == j)
       printf("\nNo se encontr?? ninguna coincidencia");
 getchar();
 goto lazo;  
         
         
 default:
     printf("\n...ERROR!");
 goto lazo;
 }
 
getchar();
return 0;
}

     .....sigue comentando.


29-Jun-2012 20:58
Rudi Merlos Carrion

Muchas gracias Pablo!!!
Has sido de gran ayuda. Pero me has dejado un poco desconcertado con lo de "goto" ya que este código es tuyo. está en la sección: Primer ejercicio Capítulo 5: Arrays y Estructuras. Yo soy bastante novato así que partí de tu código (que me pareció bastante razonable) y empezé a hacer pruebas como, por ejemplo, lo de:

case 'a':   cuando yo digo en un printf "pulse 'A' para agregar canción". Bien, yo queria que funcionase tanto con 'a' como con 'A' así que probé:

case ('A' || 'a'):  y tamblén   case 'A' || 'a':    pero eso no funciona. Así que me decidí por minúscula para que fuera más cómodo.

También he intentado no poner goto pero aún soy demasiado novato. Es cierto que el programa es muy inestable, sobre todo cuando no haces las opciones en orden.

Bueno, aquí el nuevo código:

#include <stdio.h>
#include <string.h>

struct
{
   char artist[80], titulo[80];
   int duracion, size;
}info[100];

int main(){
   
   char c, txt[40];
   int i, j, n;
   
   printf("\n   \"MENÚ\"\n\n");
   printf("Pulse \"A\" para agregar una nueva canción\n");
   printf("Pulse \"T\" para mostrar todos los títulos\n");
   printf("pulse \"B\" para buscar\n");
   printf("Pulse \"S\" para salir\n");
   
   lazo: printf("\n\nIntroduzca una opción: ");
   c = getchar();
   getchar();
   
   switch (c){
      case 'a':
        lazo1: printf("\n\n¿Cuantas canciones va a guardar?  ");
        scanf("%d", &n);
        getchar();
        if (n>0 && n<=100){
           for (i=0; i<n; i++){
               printf("\n\n\tTrack No. %d", i+1);
                   
               printf("\nNombre del artista: ");
               gets(info[i].artist);
               printf("Titulo de la canción: ");
               gets(info[i].titulo);
                   
               printf("Duración en segundos: ");
               scanf("%d", &info[i].duracion);
               printf("Tamaño en Kb: ");
               scanf("%d", &info[i].size);
               getchar();
           }
           printf("\n\n\tSALIDA");
           for(i=0; i<n; i++){
              printf("\n\n\tTrac No. %d\n", i+1);
              printf("Título: %s", info[i].titulo);
              printf("\nArtista: %s", info[i].artist);
              printf("\nDuración: %d", info[i].duracion);
              printf("\nTamaño: %d", info[i].size);
           }
        goto lazo;
        }
        else
           printf("\nTeclee un número entre el uno y el 100");
      goto lazo1;    
      case 't':
        printf("\nLista de canciones:\n");
        for(i=0; i<n; i++){
           printf("%d - %s\n", (i+1), info[i].titulo);
           if (n == 0)
               printf("No se encontró ninguna canción");
           }

        goto lazo;    
           
      case 'b':
        printf("\nBuscador: ");
        getchar();
        gets(txt);
           
        for (i=0, j=0; i<n; i++, j++){
            if (strstr(info[i].artist, txt) || strstr(info[i].titulo, txt) != NULL){
               printf("\nSe encontró coincidencia en Track No. %d\n", i+1);
               j--;
            }
        }
            if (i == j)
               printf("\nNo se encontró ninguna coincidencia");
        goto lazo;
       
      case 's':
        break;
                       
      default:
        printf("\n...ERROR!");
        goto lazo;
   }
   
getchar();
return 0;
}

Saludos!!!


30-Jun-2012 21:45
Pablo Rampa

  Hola Rudi!
Había dejado olvidado este ejercicio, pero gracias a tí recordé
que lo tenía pendiente.    
Sólo me quedó un detallito: cuando se introduce una opción no
válida muestra varias veces el mensaje correspondiente.  
Si gustas, héchale un vistazo al último post de "Primer ejercicio
Capítulo 5: Arrays y Estructuras". Ahí sustituyo los GOTO, mejoro
el uso de SCANF, GETS y algunotro detalle.

  Saludos! y ...sigue comentando.






(No se puede continuar esta discusión porque tiene más de dos meses de antigüedad. Si tienes dudas parecidas, abre un nuevo hilo.)