cunsigned-long-long-int

What is the best way to ensure a user only enters natural numbers?


Just started learning C, and it would be great if you could help me with the following:

I just wrote a program that calculates the factorial of a natural number entered by the user. If the number is negative or a character, it should notify the user with the message You have not entered a natural number.. This message comes from the function check_if_valid_value.

So far, it displays that message when entering characters, but doesn't seem to work with negative values. I thought casting the variable as long long unsigned would do the trick, but doesn't seem to be the case. The thing is the scanf() function returns a 0 so not sure why the program doesn't run the function check_if_valid_value so that it returns the message:You have not entered a natural number.

I am looking forward to reading any suggestions to improve this piece of code!

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

void check_if_valid_value(int value_entered)
{
        if (value_entered != 1) 
        {
                printf("You have not entered a natural number.\n");
                exit(1);
        }
}          

void do_the_factorial(int p)
{  
        int i;
        unsigned long long int factorial=1;

        for (i = 1; i <= p; ++i)
        {
                factorial=factorial*i;
                printf("%llu\n", factorial);
        }
}


int main(void)
{
        int value_entered, p;

        printf("Enter a natural number:");

        value_entered=scanf("%llu",&p);

        check_if_valid_value(value_entered);

        do_the_factorial(p);

        return 0;
}

Solution

  • Problems with your code:

    You could also start the factorial loop at 2, since multiplying by 1 is mostly useless. So we have:

    #include <stdio.h>
    #include <stdlib.h>
    
    void check_if_valid_value(int successful_conversions)
    {
            if (successful_conversions != 1)
            {
                    printf("You have not entered a natural number.\n");
                    exit(1);
            }
    }
    
    void do_the_factorial(unsigned int p)
    {
            unsigned int i;
            unsigned long long int factorial=1;
    
            for (i = 2; i <= p; ++i)
            {
                    factorial=factorial*i;
            }
            printf("%llu\n", factorial);
    }
    
    int main(void)
    {
            int successful_conversions;
            unsigned int p;
    
            printf("Enter a natural number:\n");
            successful_conversions=scanf("%u",&p);
            check_if_valid_value(successful_conversions);
            do_the_factorial(p);
            return 0;
    }
    

    A word of caution: scanning %u allows the number to have a sign, which can be negative. If you enter -1 then p will be the largest positive unsigned integer, UINT_MAX. Then do_the_factorial() will enter a very long loop. You should add some check if p is small enough so the factorial of p does not exceed the range of unsigned long long.

    If you want to test the input more stringently, you should learn how to read in a short string and then test whether the string consists entirely of decimal digits. As a starting point, look at fgets().