Factorial in C: Loops, Functions, Recursion and Overflow

Factorial in C means multiplying the integers from 1 through a nonnegative integer n. The empty product is 0! = 1. For example, 5! = 1 × 2 × 3 × 4 × 5 = 120. Use an integer type and check before multiplying: neither recursion nor a wider type removes the possibility of overflow.

Descending integer factors illustrate factorial calculation.

For-loop program with checked multiplication

Enter one decimal integer from 0 to 100 in stdin. Surrounding whitespace and leading zeros are accepted; signs, decimals, multiple tokens and negative numbers are rejected. The limit of 100 is a teaching/input-work bound, not a promise that 100! fits. The result must also fit unsigned long long. On a 64-bit unsigned long long, 20! fits and 21! does not. Wider implementations may accept larger results. The program reports an error rather than printing a wrapped answer.

#include <stdio.h>
#include <ctype.h>
#include <limits.h>

/* One unsigned decimal token, surrounding whitespace, then EOF. */
static int read_bounded(unsigned int *out, unsigned int limit) {
    int ch;
    unsigned int value = 0;
    do { ch = getchar(); } while (ch != EOF && isspace(ch));
    if (ch < '0' || ch > '9') return 0;
    do {
        unsigned int digit = (unsigned int)(ch - '0');
        if (value > limit / 10 ||
            (value == limit / 10 && digit > limit % 10)) return 0;
        value = value * 10 + digit;
        ch = getchar();
    } while (ch >= '0' && ch <= '9');
    while (ch != EOF && isspace(ch)) ch = getchar();
    if (ch != EOF) return 0;
    *out = value;
    return 1;
}

int main(void) {
    unsigned int n;
    if (!read_bounded(&n, 100)) {
        fputs("Enter one whole number from 0 to 100.\n", stderr);
        return 1;
    }
    unsigned long long result = 1;
    for (unsigned int i = 2; i <= n; ++i) {
        if (result > ULLONG_MAX / i) {
            fputs("Factorial exceeds ULLONG_MAX.\n", stderr);
            return 1;
        }
        result *= i;
    }
    printf("%u! = %llu\n", n, result);
    return 0;
}

Run for-loop factorial online

Sample input

5

Expected output

Reference output for the displayed program, not a live execution result.

5! = 120

read_bounded builds the value a digit at a time, checking the limit before multiplication. It reads the whole supplied stdin through EOF; this is a batch-input example, not an interactive prompt. isspace receives either a value returned by getchar or is not called for EOF, avoiding negative-character misuse.

For a positive multiplier i, result > ULLONG_MAX / i detects whether the next multiplication would exceed the type's range before it happens. Unsigned wraparound is defined by C, but it is not the mathematical factorial. Signed overflow would be undefined behavior. Checking after the multiply is too late.

While-loop version

The arithmetic and input policy are unchanged. The counter starts at 2 and advances only after a safe multiplication. When n is 0 or 1, the loop does not execute, leaving the answer 1.

#include <stdio.h>
#include <ctype.h>
#include <limits.h>

/* One unsigned decimal token, surrounding whitespace, then EOF. */
static int read_bounded(unsigned int *out, unsigned int limit) {
    int ch;
    unsigned int value = 0;
    do { ch = getchar(); } while (ch != EOF && isspace(ch));
    if (ch < '0' || ch > '9') return 0;
    do {
        unsigned int digit = (unsigned int)(ch - '0');
        if (value > limit / 10 ||
            (value == limit / 10 && digit > limit % 10)) return 0;
        value = value * 10 + digit;
        ch = getchar();
    } while (ch >= '0' && ch <= '9');
    while (ch != EOF && isspace(ch)) ch = getchar();
    if (ch != EOF) return 0;
    *out = value;
    return 1;
}

int main(void) {
    unsigned int n;
    if (!read_bounded(&n, 100)) {
        fputs("Enter one whole number from 0 to 100.\n", stderr);
        return 1;
    }
    unsigned long long result = 1;
    unsigned int i = 2;
    while (i <= n) {
        if (result > ULLONG_MAX / i) {
            fputs("Factorial exceeds ULLONG_MAX.\n", stderr);
            return 1;
        }
        result *= i;
        ++i;
    }
    printf("%u! = %llu\n", n, result);
    return 0;
}

Run while-loop factorial online

Sample input

5

Expected output

Reference output for the displayed program, not a live execution result.

5! = 120

Reusable factorial function

This function separates arithmetic from input/output. A return value of 1 means success and writes the result through out; 0 means overflow and leaves that output unchanged. The caller must pass a valid output pointer and n within the demonstrated 0–100 contract. The complete example below does both.

#include <stdio.h>
#include <ctype.h>
#include <limits.h>

/* One unsigned decimal token, surrounding whitespace, then EOF. */
static int read_bounded(unsigned int *out, unsigned int limit) {
    int ch;
    unsigned int value = 0;
    do { ch = getchar(); } while (ch != EOF && isspace(ch));
    if (ch < '0' || ch > '9') return 0;
    do {
        unsigned int digit = (unsigned int)(ch - '0');
        if (value > limit / 10 ||
            (value == limit / 10 && digit > limit % 10)) return 0;
        value = value * 10 + digit;
        ch = getchar();
    } while (ch >= '0' && ch <= '9');
    while (ch != EOF && isspace(ch)) ch = getchar();
    if (ch != EOF) return 0;
    *out = value;
    return 1;
}

int factorial(unsigned int n, unsigned long long *out) {
    unsigned long long value = 1;
    for (unsigned int i = 2; i <= n; ++i) {
        if (value > ULLONG_MAX / i) return 0;
        value *= i;
    }
    *out = value;
    return 1;
}

int main(void) {
    unsigned int n;
    if (!read_bounded(&n, 100)) {
        fputs("Enter one whole number from 0 to 100.\n", stderr);
        return 1;
    }
    unsigned long long result;
    if (!factorial(n, &result)) {
        fputs("Factorial exceeds ULLONG_MAX.\n", stderr);
        return 1;
    }
    printf("%u! = %llu\n", n, result);
    return 0;
}

Run factorial function online

Sample input

5

Expected output

Reference output for the displayed program, not a live execution result.

5! = 120

Recursive factorial and the base case

The recurrence is n! = n × (n − 1)! with a base case for 0 and 1. A recursive result is checked before the caller multiplies it. Keep the caller's bounded input: C does not guarantee unlimited call-stack space or tail-call optimization.

#include <stdio.h>
#include <ctype.h>
#include <limits.h>

/* One unsigned decimal token, surrounding whitespace, then EOF. */
static int read_bounded(unsigned int *out, unsigned int limit) {
    int ch;
    unsigned int value = 0;
    do { ch = getchar(); } while (ch != EOF && isspace(ch));
    if (ch < '0' || ch > '9') return 0;
    do {
        unsigned int digit = (unsigned int)(ch - '0');
        if (value > limit / 10 ||
            (value == limit / 10 && digit > limit % 10)) return 0;
        value = value * 10 + digit;
        ch = getchar();
    } while (ch >= '0' && ch <= '9');
    while (ch != EOF && isspace(ch)) ch = getchar();
    if (ch != EOF) return 0;
    *out = value;
    return 1;
}

int factorial_recursive(unsigned int n, unsigned long long *out) {
    if (n < 2) { *out = 1; return 1; }
    unsigned long long previous;
    if (!factorial_recursive(n - 1, &previous) ||
        previous > ULLONG_MAX / n) return 0;
    *out = previous * n;
    return 1;
}

int main(void) {
    unsigned int n;
    if (!read_bounded(&n, 100)) {
        fputs("Enter one whole number from 0 to 100.\n", stderr);
        return 1;
    }
    unsigned long long result;
    if (!factorial_recursive(n, &result)) {
        fputs("Factorial exceeds ULLONG_MAX.\n", stderr);
        return 1;
    }
    printf("%u! = %llu\n", n, result);
    return 0;
}

Run recursive factorial online

Sample input

5

Expected output

Reference output for the displayed program, not a live execution result.

5! = 120

For input 4 the calls descend f(4) → f(3) → f(2) → f(1). The base case returns 1; unwinding produces 2, then 6, then 24. Omitting the base case or allowing negative arguments to recurse downwards would prevent termination. Here unsigned input alone is not the validation policy: the parser explicitly rejects the minus sign rather than converting it to a large unsigned value.

Step for n = 5 Multiplier Accumulated result
Initialize — 1
First multiply 2 2
Second 3 6
Third 4 24
Fourth 5 120

Sum of a factorial series

This is a different task: compute 0! + 1! + ... + n!, including 0!. For n = 5 the terms are 1, 1, 2, 6, 24 and 120, whose sum is 154. Reuse the previous factorial instead of recalculating each term. Check both multiplication and addition; a sum can overflow even when its individual terms fit.

#include <stdio.h>
#include <ctype.h>
#include <limits.h>

/* One unsigned decimal token, surrounding whitespace, then EOF. */
static int read_bounded(unsigned int *out, unsigned int limit) {
    int ch;
    unsigned int value = 0;
    do { ch = getchar(); } while (ch != EOF && isspace(ch));
    if (ch < '0' || ch > '9') return 0;
    do {
        unsigned int digit = (unsigned int)(ch - '0');
        if (value > limit / 10 ||
            (value == limit / 10 && digit > limit % 10)) return 0;
        value = value * 10 + digit;
        ch = getchar();
    } while (ch >= '0' && ch <= '9');
    while (ch != EOF && isspace(ch)) ch = getchar();
    if (ch != EOF) return 0;
    *out = value;
    return 1;
}

int main(void) {
    unsigned int n;
    if (!read_bounded(&n, 100)) {
        fputs("Enter one whole number from 0 to 100.\n", stderr);
        return 1;
    }
    unsigned long long term = 1, sum = 1;
    for (unsigned int i = 1; i <= n; ++i) {
        if (term > ULLONG_MAX / i) {
            fputs("Series exceeds ULLONG_MAX.\n", stderr);
            return 1;
        }
        term *= i;
        if (sum > ULLONG_MAX - term) {
            fputs("Series exceeds ULLONG_MAX.\n", stderr);
            return 1;
        }
        sum += term;
    }
    printf("0! + ... + %u! = %llu\n", n, sum);
    return 0;
}

Run factorial series online

Sample input

5

Expected output

Reference output for the displayed program, not a live execution result.

0! + ... + 5! = 154

Integer limits, complexity and mistakes

Method Arithmetic operations Auxiliary space
For loop / while loop / iterative function O(n) O(1)
Recursion O(n) O(n) call frames
Series with a reused term O(n) O(1)

These counts treat fixed-width operations as constant-time. Big-integer arithmetic has a different cost model. A 32-bit signed int can hold 12! but not 13!; C does not require int to be 32 bits. unsigned long long has at least 64 value bits under C17; inspect ULLONG_MAX on the implementation you use. Do not describe 20 as an unconditional C language limit.

Initialize factorial to 1, not 0. Do not use a floating-point value and cast it back to an integer to hide overflow: rounding can lose exactness. Negative-integer factorial is not defined by this elementary product, and this program intentionally rejects it. The gamma function is a separate mathematical topic, not a reason to silently accept negative integers here.

For exact results larger than the type supports, use a reviewed big-integer implementation. This page does not bundle one or claim that changing int to long long supports arbitrarily large inputs.

Predict the output for 0, 1 and 6: the factorials are 1, 1 and 720; the series sums are 1, 2 and 874. Then try -1, 3.5 and two input tokens: each must be rejected. On a 64-bit unsigned long long, try 20 and 21 and explain why only the former succeeds.

Review functions, program structure, and loop patterns. All run links load the exact displayed source and sample stdin in the online C compiler. Output printed on this page is a reference, not evidence of a current sandbox run.

Frequently asked questions

Why is 0! equal to 1?

It is the empty product. It also keeps the recurrence 1! = 1 × 0! consistent and makes counting formulas work at zero.

Is recursion faster than a loop?

Not inherently. Both perform O(n) multiplications, while this recursive version adds call frames. Use the loop when you only need the result and the recurrence when studying recursion.

Why not use scanf with an unsigned format?

A numeric conversion alone does not enforce this page's complete-input policy. The parser here rejects signs, extra tokens and out-of-range values before arithmetic, rather than accepting a valid numeric prefix and ignoring the rest.

Related examples