Jump to content

scanf behave weird with %c for char input, but not with %d for char(digit) input

- - - - -

  • Please log in to reply
3 replies to this topic

#1
ajiten

ajiten

    Newbie

  • Members
  • Pip
  • 2 posts
#include<stdio.h>
#include<conio.h>
void main()
{
  char c;
  int choice;
  clrscr();
  while(choice)
  {
    scanf("%c", &c);//Q.1>behaves weird as if newline is input for 'c', for second time 
                                 //onwards loop run. 
                                //Q.2> But behaves ok, if a digit (0-9) is entered with 
                                //scanf("%d", &c); 
                                //Q.3> However, this modification eats up the display of 
                                //value of 'choice' entered via keyboard.
                                //Q.4>Also, this change causes infinite loop if a non-digit is entered 
                                //for 'c'.
    printf("\n ascii code of %c is %d",c,c);
    printf("\n Enter choice");
    scanf("%d", &choice);
  }
  getch();
}
Any help that answers all 4 questions stated in comments above is highly welcome.
Jiten

Edited by Alexander, 08 April 2011 - 07:04 AM.
Code blocks (# button)


#2
Alexander

Alexander

    It's Science!

  • Moderators
  • 4,118 posts
  • Location:Vancouver, Eh! Cleverness: 200
The problem is that the newline character '\n', or ASCII 10 will remain in the standard input buffer after you accept any input. This is because you are telling scanf to scan one token of type %c from standard input, you will not be touching the newline. This newline will now be free to fill the next request for input. If you are asking for an integer or other numeric then it will not even accept the newline and can cause undetermined behaviour such as infinite loops.

One method to prevent this is by accepting all input in to a buffer, and only then scanning it (sscanf) to prevent any further data in the buffer. You can then flush the standard input with getchar(), although this will not be needed for smaller output.

An example to safely retrieve an integer from input, with error checking if required:

int choice;
char line[255];    
fgets(line, sizeof(line), stdin);
while(sscanf(line, "%d", &choice) != 1) { //1 match of defined specifier on input line
  printf("You have not entered an integer.\n");
  fgets(line, sizeof(line), stdin);
}
You can as well simply use getchar() after scanf(), in my humble opinion this is a hack to cover the problem of unknown input beforehand (why the above solution is better)
scanf("%d", &foo);
getchar();
or maybe a bit more precise:
int ch;
while ((ch = getchar()) != '\n' && ch != EOF)  ;
Or simply tell scanf to scan past the token any whitespace, although not store any of it:
scanf("%c%*[ \n\t]", &c);
With this it would be hard to test the success of the input as scanf can return any number of count.

Edited by Alexander, 08 April 2011 - 02:08 PM.

Be sure to read the updated FAQ! || Health is achieved through the same 10,000 steps.
If a suggested code/method fails, informing us is less important than telling us why or what errors occurred.

#3
ajiten

ajiten

    Newbie

  • Members
  • Pip
  • 2 posts
Thanks for respone.

I have a doubt, it is in your answer only. You stated: >'If you are asking for a decimal, then it will not even accept the newline and can cause undetermined behaviour such as infinite loops.'

Can you kindly elaborate it.

Also, I made a change in the program:

I modified it to fill in by the scanf() in an array instead, and want to display the current location and the next's contents. The output varies in the case of decimal/char input. But, the char input also does not show newline character's code as 10, instead 0 is shown.
If possible, kindly explain this too.
The code is stated below.

Best Regards,
Jiten

#include<stdio.h>
#include<conio.h>
void main()
{
char c[10];
int choice, i=0, j;
clrscr();
while(choice)
{
scanf("%d", &c[i]);
j=i+1;
printf("\nAscii code of %c:%c|| %c:%c is %d:%d", c[i++],c[j],c[i],c[j],c[i],c[j]);
printf("\n Enter choice");
scanf("%d", &choice);
}
}

#4
Alexander

Alexander

    It's Science!

  • Moderators
  • 4,118 posts
  • Location:Vancouver, Eh! Cleverness: 200

Quote

I have a doubt, it is in your answer only. You stated: >'If you are asking for a decimal, then it will not even accept the newline and can cause undetermined behaviour such as infinite loops.'

Can you kindly elaborate it.
If you scan a char and then an integer in a loop, the remaining newline will skip the integer and plug in to the char, causing an infinite loop or any number of symptoms.

Quote

If possible, kindly explain this too.
The code is stated below.
If your compiler supports proper warnings, it should state something similar to "warning: int format, different type arg (arg 2)"

You are essentially scanning an integer (4 or 8 bytes) in to an array of chars (1 byte), therefor you are overwriting memory and invoking undefined behaviour. It likely displayed 0 because that was what was past your last array element, although nothing says it has to be 0, it could be random.
Be sure to read the updated FAQ! || Health is achieved through the same 10,000 steps.
If a suggested code/method fails, informing us is less important than telling us why or what errors occurred.




1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users