Home > Software engineering >  While statement in c goes into infinite loop when float value is assigned to int?
While statement in c goes into infinite loop when float value is assigned to int?

Time:09-07

So this is the code:

int num, counter = 1;

while (counter == 1)
{
    printf_s("Enter a 5-digit integer :");
    scanf_s("%d",&num);

    if (num < 10000 || num > 99999)
    {
        puts("Please make sure the number you entered has 5 digits!\n");
    }
    else if((num0000 - num000)/10000 == num && (num0-num) == (num000-num00)/100 )
    {
        printf_s("%d is a 5-digit palindrome!\n",num);
        puts("Do you wish to continue? 1 = continue 0 = stop");
        scanf_s("%d",&counter);
    }
    else
    {
        printf_s("%d is not a palindrome!\n",num);
    }
}

I didn't expect it to do anything useful with floats since I didn't add anything for it to do so, but why does it enter an infinite loop saying "Enter a 5 digit integer : (number) isn't a palindrome!"?

edit: Turns out I forgot to add what type of variable num and counter was. And somehow called while a function.

CodePudding user response:

While function in c goes into infinite loop when float value is assigned to int?

Code fails to check the return value of scanf_s("%d",&num);

When non-numeric text for an int, like "123.456" is entered, num takes on the value 123 and 1 is returned. The '.' is not consumed. scanf_s("%d",&num); repeatedly fails on subsequent calls as it attempts to read ".456". and num is not changed - infinite loop.

Instead, check the return value of input functions.

// scanf_s("%d",&num);
if (scanf_s("%d",&num) != 1) {
  puts("Fail");
  break;
}

Or use fgets() to read an entire line (usually). @Some programmer dude

CodePudding user response:

I just ran a test on scanf.

For 123.456 I thought it would return -1. But it returns 1 and num will be 123. It also does the same for 123x.

Then, I realized that is probably wants for scanf with file input.

But, given the context of checking for valid user input (from stdin), I'd say that's bad and I'd use strtol with the requisite checks instead.


Here's some code that shows the difference:

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

void
doscanf(const char *str)
{
    int ret;
    int num;

    errno = 0;
    ret = sscanf(str,"%d",&num);

    printf("doscanf: str='%s' ret=%d num=%d -- %s\n",
        str,ret,num,strerror(errno));
}

void
dostrtol(const char *str)
{

    errno = 0;

    char *cp;
    int num = strtol(str,&cp,10);
    int valid = (*cp == 0);

    printf("dostrtol: num=%d str='%s' cp='%s' valid=%d -- %s\n",
        num,str,cp,valid,strerror(errno));
}

int
main(void)
{
    const char *strs[] = {
        "123",
        "456",
        "",
        "123.456",
        "123x",
        "x123",
        NULL,
    };

    int sep = 0;
    for (const char **str = strs;  *str != NULL;    str) {
        if (sep)
            printf("\n");
        sep = 1;

        doscanf(*str);
        dostrtol(*str);
    }

    return 0;
}

Here is the program output:

doscanf: str='123' ret=1 num=123 -- Success
dostrtol: num=123 str='123' cp='' valid=1 -- Success

doscanf: str='456' ret=1 num=456 -- Success
dostrtol: num=456 str='456' cp='' valid=1 -- Success

doscanf: str='' ret=-1 num=1 -- Success
dostrtol: num=0 str='' cp='' valid=1 -- Success

doscanf: str='123.456' ret=1 num=123 -- Success
dostrtol: num=123 str='123.456' cp='.456' valid=0 -- Success

doscanf: str='123x' ret=1 num=123 -- Success
dostrtol: num=123 str='123x' cp='x' valid=0 -- Success

doscanf: str='x123' ret=0 num=0 -- Success
dostrtol: num=0 str='x123' cp='x123' valid=0 -- Success

Side note: Your "is palindrome" algorithm is hardwired to take only 5 digit numbers.

That's okay, but a bit restrictive (and unusual). Here's a test program that shows a generalized algorithm:

#include <stdio.h>

// orig -- OP original code (restricted/hardwired to 5 digit numbers)
int
orig(int num)
{
    int palflg;

    palflg = (num0000 - num000)/10000 == num &&
        (num0-num) == (num000-num00)/100;

    return palflg;
}

// ispal -- generalized to any number
int
ispal(int num)
{
    int digits[100];
    int left = 0;
    int right = 0;
    int palflg = 1;

    // split number into digits
    for (;  num != 0;  num /= 10)
        digits[right  ] = num % 10;

    // compare outer digits (working inward)
    --right;
    for (;  left <= right;    left, --right) {
        palflg = (digits[left] == digits[right]);
        if (! palflg)
            break;
    }

    return palflg;
}

int
main(void)
{
    int numbers[] = {
        12345, 12312, 12321, 56465,
#ifndef RESTRICT
        0, 1, 23, 123, 232, 1221, 12321, 123321,
#endif
    };

    for (int idx = 0;  idx < sizeof(numbers) / sizeof(numbers[0]);    idx) {
        int num = numbers[idx];

        int palflg = ispal(num);
        int origflg = orig(num);

        printf("d -- ispal=%s orig=%s -- %s\n",
            num,
            palflg ? "is" : "not",
            origflg ? "is" : "not",
            (palflg == origflg) ? "PASS" : "FAIL");
    }

    return 0;
}

Here is the program output:

     12345 -- ispal=not orig=not -- PASS
     12312 -- ispal=not orig=not -- PASS
     12321 -- ispal=is orig=is -- PASS
     56465 -- ispal=is orig=is -- PASS
         0 -- ispal=is orig=is -- PASS
         1 -- ispal=is orig=not -- FAIL
        23 -- ispal=not orig=not -- PASS
       123 -- ispal=not orig=not -- PASS
       232 -- ispal=is orig=not -- FAIL
      1221 -- ispal=is orig=not -- FAIL
     12321 -- ispal=is orig=is -- PASS
    123321 -- ispal=is orig=not -- FAIL
  • Related