3

I'm trying to input a character into a linked list, where the character can be 'A','a','G','g','T','t','C' or 'c'.

I'm not yet familiar with C and I know I've screwed something up here:

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 is initialized with a junk value, in this case 'q'.

Entering 'x' exits the loop, entering any acceptable value calls AddToSequence(), and any unacceptable value gets a warning.

For some reason, no matter what value is in newChar, it will jump to the else. It will also jump straight past the scanf without waiting for entry from the user and do two loops every time it loops. Can anyone tell me where I'm going wrong?

Full program:

#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 ;
}
ljedrz
  • 20,316
  • 4
  • 69
  • 97
PatPat
  • 55
  • 1
  • 1
  • 7

4 Answers4

14

You don't handle the newline. The %c specifier doesn't skip blanks. Try:

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

Or maybe add an explicit test.

scanf(...);
if (newChar == '\n')
    continue;
cnicutar
  • 178,505
  • 25
  • 365
  • 392
  • One more little snag. Scanf still seems to be grabbing characters a loop late: Input '1' (menu), 'A' (for input), 'B' (to fail), 'C' (for input) seems to fail after input 'A', work after input 'B' and fail again after input 'C' where 'A' and 'C' are meant to pass. – PatPat Dec 04 '12 at 20:15
  • 1
    @PatPat Like I commented before, `" %c"` is more robust. – cnicutar Dec 04 '12 at 20:30
  • One final snag, It now seems to be filling the list weirdly. 8 entries appear to go in fine (AAAACCCC), but the Display() function tells me the list only contains the single character A and the Percentage function is telling me that A, G, T and C all take up 12.5% of the list each (impossible). That was working fine earlier, so I have no idea what's going on now. Pointers. Damn them. – PatPat Dec 04 '12 at 20:46
  • 1
    @PatPat Your `AddToSequence` looks botched. For example, I don't think you should have braces (`{`) on that while; you really only need to do `loc=loc->point;` there. and assign to loc->point **outside** the loop. – cnicutar Dec 04 '12 at 20:49
  • Ah, so this? while(loc->point!=NULL) NEW LINE loc=loc->point; NEW LINE /*End While*/ NEW LINE loc->point=first; ~~~~ Working perfectly. Thanks so much! – PatPat Dec 04 '12 at 20:55
6

add space to "%c" to catch the newline character. the space charcter is used to catch space characters, tabulations, newline

scanf("%c ",&newChar);
MOHAMED
  • 41,599
  • 58
  • 163
  • 268
  • Another person put the space before, you put it after. Does it matter? – PatPat Dec 04 '12 at 20:08
  • the right one is after and not before because you are typing the charchter and then the new line – MOHAMED Dec 04 '12 at 20:12
  • @PatPat I think you should put it before the %c. It will eat the newline whenever needed (for example a previous `%d` will break the code in this answer). On the other hand, if you use " %c" you can't construct a scenario to break it. – cnicutar Dec 04 '12 at 20:14
  • One more snag, It now seems to be filling the list weirdly. 8 entries appear to go in fine (AAAACCCC), but the Display() function tells me the list only contains the single character A and the Percentage function is telling me every that A, G, T and C all take up 12.5% of the list each (impossible). That was working fine earlier, so I have no idea what's going on now. – PatPat Dec 04 '12 at 20:36
4

You're leaving the '\n' on stdin:

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

Or since you're already using scanf() you can tell scanf itself to take care of the newline character:

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

Even better you can leave it open by adding a space after the format specificer:

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

Just in case the user wants to do something like: 2<tab key><enter key>

Regardless of how you handle it, the point is you need to consume the newline character.

Mike
  • 47,263
  • 29
  • 113
  • 177
0

Use

newChar=getche();

This is a nonstandard function that gets a character from the keyboard, echoes to screen.