Search code examples
cwhile-loopinfinite-loopunsigned

Am I correct in figuring out why this while loop is infinite?


I wrote a simple program (included below) that takes a 5-digit number, reverses and prints it.

#include <stdio.h>
#include <limits.h>
#include <math.h>
int main(void)
{
        unsigned short num, revnum, digit, count;
        count = 4;
        revnum = 0;
        fprintf(stdout, "Enter a five digit number in range [0 - %hu]: ", USHRT_MAX);
        fscanf(stdin, "%hu", &num);
        while (count >= 0) {
                digit = num % 10;
                num = num / 10;
                revnum += digit * pow(10, count);
                count--;
        }
        fprintf(stdout, "The number with digits reversed is %hu.\n", revnum);
        return 0;
}

However the program when run, doesn't return anything post taking input and storing it in the num variable. It didn't crash/exit either. There is nothing wrong with the while loop's body, so I suspected an infinite loop and wrote a small program just to print out the count variable from a similar while loop

#include <stdio.h>
int main(void)
{
        unsigned short count;
        count = 4;
        while (count >= 0) {
                printf("%hu", count);
                count--;
        }
        return 0;
}

This indeed turns out to be an infinite loop... a part of the output is:

...300653005530045300353002530015300052999529985299752996529955299452993529925299152990529895298852987529865298552984529835298252981529805297952978529775297652975529745297352972529715297052969529685296752966529655296452963529625296152960529595295852957529565295552954529535295252951529^C

My assumption is that the culprit is the count's type which is unsigned short. As this means it can't decrement below 0, so the final count-- when count already == 0 sets its value to USHRT_MAX and thus can never terminate the loop. Am I correct?


Solution

  • Your assumption is correct: being your variable unsigned it won't ever be evaluated as negative.

    In your case, if you decrement the count variable when it is equal to 0 you get the value 65535 (USHRT_MAX).

    The trivial solution is getting rid of the unsigned keyword:

    short count = 4;
    

    This solution is the best for the basic code provided in the question. Anyway, since in the "real code" could happen that changing the type of the counter is not an option, a check on count == 0 before decrementing could be the solution (credits to @Elijan9):

    while (true)
    {
        /* ...; */
         if (count == 0)
            break;
        --count;
     }