Problemas con la entrada de caracteres usando scanf()

6 minutos de lectura

avatar de usuario
PatPat

Estoy tratando de ingresar un carácter en una lista enlazada, donde el carácter puede ser ‘A’, ‘a’, ‘G’, ‘g’, ‘T’, ‘t’, ‘C’ o ‘c’.

Todavía no estoy familiarizado con C y sé que arruiné algo aquí:

do{
  printf ("\nEnter a new nucleotide: \n");
  scanf("%c",&newChar);
          /* Checking */
  if(newChar == 'A' ||
     newChar == 'a' || 
     newChar == 'G' || 
     newChar == 'g' || 
     newChar == 'T' || 
     newChar == 't' || 
     newChar == 'C' || 
     newChar == 'c' )
  {
    AddToSequence(newChar);
    size++;
  } else {
    printf ("\nBad Element");
  }
}while(newChar != 'x');

newChar se inicializa con un valor basura, en este caso ‘q’.

Ingresar ‘x’ sale del ciclo, ingresar cualquier valor aceptable llama a AddToSequence(), y cualquier valor inaceptable recibe una advertencia.

Por alguna razón, no importa qué valor tenga newChar, saltará al otro. También saltará directamente más allá del scanf sin esperar la entrada del usuario y hará dos bucles cada vez que lo haga. ¿Alguien puede decirme dónde me estoy equivocando?

programa completo:

#include<stdio.h>
#include<stdlib.h>

/*Structure declaration for the node*/
struct node{
   char nucleotide;
   struct node *point;
}*start;

/* Adds a nucleotide to the chain. Creates a new linked list if no chain exists exists.*/
void AddToSequence(char nucleotide){
  struct node *loc, *first;
  //Dynamic memory is been allocated for a node
  first=(struct node*)malloc(sizeof(struct node));
  first->nucleotide=nucleotide;
  first->point=NULL;
  if(start==NULL){
    /*If list is empty*/
    start=first;
  }else{
    /*Element inserted at the end*/
    loc=start;
    while(loc->point!=NULL){
      loc=loc->point;
      loc->point=first;
    }
  }
}

/* Display elements */
void Display(){
  struct node *loc;
  if(start == NULL){
    printf ("\n\nList is empty");
    return;
  }
  loc=start;
  printf("\n\nList is : ");
  while(loc!=NULL){
    printf ("%c", loc->nucleotide);
    loc=loc->point;
  }
  printf ("\n");
}

/* Finds and displays percentage of the chain made up of each nucleotide. */
void Percentage(int size){
  struct node *loc;
  if(start == NULL){
    printf ("\n\nList is empty");
    return;
  }
  loc=start;
  printf("\n\nList is : ");
  int A = 0, G =0, T =0, C = 0;
  double Adouble = 0, Gdouble =0, Tdouble=0, Cdouble=0;
  while(loc!=NULL){
    if(loc->nucleotide=='A' || 'a'){A++;}
    if(loc->nucleotide=='G' || 'g'){G++;}
    if(loc->nucleotide=='T' || 't'){T++;}
    if(loc->nucleotide=='C' || 'c'){C++;}    
    loc=loc->point;   
  }
  printf ("\n"); 

  /* Convert to double for percentages as int loses precision */
  Adouble =A;
  Gdouble =G;
  Tdouble =T;
  Cdouble =C; 
  Adouble =(Adouble/size)*100;
  Gdouble =(Gdouble/size)*100;
  Tdouble =(Tdouble/size)*100;
  Cdouble =(Cdouble/size)*100; 
  printf("\nA: %f", Adouble);
  printf("\nG: %f", Gdouble);
  printf("\nT: %f", Tdouble);
  printf("\nC: %f", Cdouble); 
}

/* There be dragons beyond here */
int main(){
  int navigate, size =0;
  char newChar="q";
  do{ /* Menu */
    printf("\n 1. Create / Extend Sequence\n");
    printf("\n 2. Display Sequence\n");
    printf("\n 3. Count \n");
    printf("\n 0. Exit \n");
    printf("\nPlease select an option (0 to 3)\n");
    scanf("%d",&navigate);  
    switch (navigate){
      case 0: /* Exit */
        break;
      case 1: /* Add nucleotides */
        do{
          printf ("\nEnter a new nucleotide: \n");
          scanf("%c",&newChar);
          /* Some error checking */
          if(newChar == 'A' || newChar == 'a' || newChar == 'G' || newChar == 'g' || newChar == 'T' || newChar == 't' || newChar == 'C' || newChar == 'c' ){
            AddToSequence(newChar);
            size++;
          } else {
            printf ("\nBad Element");
          }
        }while(newChar != 'x');
        break;
      case 2:
        Display();
        break;
      case 3:
        Percentage(size);
        break;
      default:
        printf ("\n\nBad choice. Please select another.\n");
    }
  } while (navigate !=0); 
  return 0 ;
}

No manejas la nueva línea. los %c el especificador no salta los espacios en blanco. Tratar:

scanf(" %c", &newChar);
    /* ^ <-- Makes `scanf` eat the newline. */

O tal vez agregar una prueba explícita.

scanf(...);
if (newChar == '\n')
    continue;

  • Una pequeña pega más. Scanf todavía parece estar agarrando caracteres un bucle tarde: la entrada ‘1’ (menú), ‘A’ (para entrada), ‘B’ (para fallar), ‘C’ (para entrada) parece fallar después de la entrada ‘A’ , funciona después de la entrada ‘B’ y vuelve a fallar después de la entrada ‘C’ donde ‘A’ y ‘C’ deben pasar.

    – PatPat

    4 de diciembre de 2012 a las 20:15

  • @PatPat Como comenté antes, " %c" es más robusto.

    – cnicutar

    04/12/2012 a las 20:30

  • Un inconveniente final, ahora parece estar llenando la lista de manera extraña. 8 entradas parecen ir bien (AAAACCCC), pero la función Display() me dice que la lista solo contiene el carácter A y la función Porcentaje me dice que A, G, T y C ocupan el 12,5 % de la lista cada uno (imposible). Eso estaba funcionando bien antes, así que no tengo idea de lo que está pasando ahora. Punteros. Malditos sean.

    – PatPat

    4 de diciembre de 2012 a las 20:46


  • @PatPat Su AddToSequence parece estropeado. Por ejemplo, no creo que debas usar frenos ({) en ese momento; realmente solo necesitas hacer loc=loc->point; allí. y asignar a loc->punto fuera de el lazo.

    – cnicutar

    4 de diciembre de 2012 a las 20:49


  • Ah, entonces esto? while(loc->punto!=NULL) NUEVA LÍNEA loc=loc->punto; NUEVA LINEA /*Terminar Mientras*/ NUEVA LINEA loc->punto=primero; ~~~~ Funciona perfectamente. ¡Muchas gracias!

    – PatPat

    4 de diciembre de 2012 a las 20:55


añadir espacio a "%c" para capturar el carácter de nueva línea. el carácter de espacio se usa para capturar caracteres de espacio, tabulaciones, nueva línea

scanf("%c ",&newChar);

  • Otra persona pone el espacio antes, tú lo pones después. ¿Importa?

    – PatPat

    4 de diciembre de 2012 a las 20:08

  • el correcto es después y no antes porque está escribiendo el charchter y luego la nueva línea

    – MOHAMED

    4 de diciembre de 2012 a las 20:12

  • @PatPat Creo que deberías ponerlo antes de %c. Se comerá la nueva línea cuando sea necesario (por ejemplo, una anterior %d romperá el código en esta respuesta). Por otro lado, si usa ” %c” no puede construir un escenario para romperlo.

    – cnicutar

    4 de diciembre de 2012 a las 20:14


  • Un inconveniente más, ahora parece estar llenando la lista de manera extraña. 8 entradas parecen ir bien (AAAACCCC), pero la función Mostrar () me dice que la lista solo contiene el carácter único A y la función Porcentaje me dice que A, G, T y C ocupan el 12.5% ​​del enumere cada uno (imposible). Eso estaba funcionando bien antes, así que no tengo idea de lo que está pasando ahora.

    – PatPat

    4 de diciembre de 2012 a las 20:36


avatar de usuario
Miguel

te vas de la '\n' en stdin:

scanf("%d",&navigate);  
getchar(); // consume the newline character
...
scanf("%c",&newChar);
getchar(); // consume the newline character

O como ya estás usando scanf() puede decirle a scanf que se ocupe del carácter de nueva línea:

scanf("%d\n", &navigate);
....
scanf("%c\n",&newChar);

Aún mejor, puede dejarlo abierto agregando un espacio después del especificador de formato:

scanf("%d ", &navigate);
....
scanf("%c ",&newChar);

En caso de que el usuario quiera hacer algo como: 2<tab key><enter key>

Independientemente de cómo lo maneje, el punto es que necesita consumir el carácter de nueva línea.

Utilizar

newChar=getche();

Esta es una función no estándar que obtiene un carácter del teclado, hace eco en la pantalla.

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad