5

I feel like I am missing something dreadfully obvious here, but I just can't seem to find the problem with my code. I am trying to use scanf to find if an input is an integer, and if it is, find the octal. If it is not an integer, then it simply prompts the user to enter again. For some reason, however, I can only seem to get the code to work if the reverse is the case, where an integer is not accepted and anything else is. Seems like it would be a simply problem to fix, but I just get infinite loops otherwise. Any help you guys could give would be appreciated.

#include <stdio.h>
enum state {success,fail,quit};
int status = fail;

int main(void)
{
int n;
char t;
do
{
printf("Enter a number between 0 and 32767: ");

if(scanf("%d%c", &n, &t) != 2 )
status = success;
}
while (status == fail);
if (status == success)
{

int oct1, oct2, oct3, oct4, oct5;

oct1 = ((((n / 8) / 8) / 8) / 8) % 8;
oct2 = (((n / 8) / 8) / 8) % 8;
oct3 = ((n / 8) / 8) % 8;
oct4 = (n / 8) % 8;
oct5 = n % 8;

printf("In octal, your number is: %d%d%d%d%d\n", oct1, oct2, oct3, oct4, oct5);
return 0;
}
}
user2760309
  • 73
  • 1
  • 4
  • 1
    Why not use `printf("In octal, your number is: %o\n", n);`? – Some programmer dude Sep 12 '13 at 11:33
  • Just by the way: the if is unneccesary,: you loop while its false and after leaving the loop (what means is true) you are asking for "is true?" – dhein Sep 12 '13 at 11:37
  • read answer: [Scanf won't execute for second time](http://stackoverflow.com/questions/17827603/scanf-wont-execute-for-second-time/17827635#17827635) from: `Regarding you logic of error detection` – Grijesh Chauhan Sep 12 '13 at 12:24

5 Answers5

1

You have a problem in that if you enter a non-numeric value, then the it will not be removed from the input buffer and will stay there forever while you try to scan for numbers.

Instead read the line separately, and then try to get the number from that line. Something like this:

for (;;)
{
    printf("Enter a number: ");

    /* Get a line of input from the user */
    char line[128];
    if (fgets(line, sizeof(line), stdin) == NULL)
    {
        /* Error reading */
        perror("fgets");
        break;
    }

    /* The `fgets` function leaves the newline in the string */
    /* Remove it by overwriting it with the string terminator */
    line[strlen(line) - 1] = '\0';

    /* Convert to a number */
    char *endptr = NULL;
    n = strtol(line, &endptr, 10);

    /* Check if a valid number was entered */
    if (endptr == line)
        printf("Not a valid number, please enter again\n");
    else if (endptr < (line + strlen(line)))
        printf("Line begins with a number, but then there is garbage\n");
    else
        break;  /* We got a valid number */
}

If you don't care about possible garbage, you could use sscanf instead, and simplify this as

for (;;)
{
    printf("Enter a number: ");

    /* Get a line of input from the user */
    char line[128];
    if (fgets(line, sizeof(line), stdin) == NULL)
    {
        /* Error reading */
        perror("fgets");
        break;
    }

    /* Try to get number as an unsigned short */
    if (sscanf(line, " %hu", &n) == 1)
        break;

    printf("Illegal number\n");
}
Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
1

Refactored your code

#include <stdio.h>

    int main(void)
    {
    int n;
    char t;
    do
    {
    printf("Enter a number between 0 and 32767: ");
    scanf("%d", &n);
    }
    while( (n < 0) || (n > 32767)) ; //check the range of the input.if not there in this range then re read input.
    printf("In octal, your number is: %o \n", n); //print octal of input with %o format specifier.
    return 0;
    }
Gangadhar
  • 10,248
  • 3
  • 31
  • 50
0

If the scanf encounters error, it implies that the parsing error is still present even if you call the scanf again i.e it parses the older user input again and does not take the new user input.

AFAIK, it is not possible to use scanf to find the errors in parsing integer. Use other appropriate functions like scanf("%s")/fgets() followed by strtol.

while (1)
{
    char input[128], *endptr;
    int value;
    scanf("%s", input);
    value = strtol(input, &endptr, 10);
    if (endptr != input)
    {
        break;
    }
    printf("input again\n");
}
user1969104
  • 2,340
  • 14
  • 15
0

All you need is this :

do
{
   printf("Enter a number between 0 and 32767: ");

   if(scanf("%d", &n) == 1 && ((n > 0) && (n < 32767)) )
     status = success;
   else
     while((t=getchar()) !='\n' && t !=EOF) ; //Eat the trailing newline
}while (status == fail);

See HERE

P0W
  • 46,614
  • 9
  • 72
  • 119
0

There are just two little errors in your code.

First,

if(scanf("%d%c", &n, &t) != 2 )
  status = success;

should be

if(scanf("%d%c", &n, &t) == 2 )
  status = success;

That's why it accepted non-integers. The other thing is that you must flush stdin if there was an error in order for scanf to read something new:

if(scanf("%d%c", &n, &t) == 2 )
  status = success;
else
  fflush(stdin);

Put this into your program and it works.

Edit: As Grijesh points out, fflush(stdin) should not be used so you have to do something more intelligent regarding the repeated scanf. Others have given some possibilities, but I leave this answer as it points out your original logic fault.

firefrorefiddle
  • 3,795
  • 20
  • 31