Skip to content

Tower of Hanoi in C

The recursive solution in plain C, stepped through beside the board — and a version with no recursion and no towers in memory at all.

On this page
  1. The recursive solution, running
  2. Run it yourself
  3. Line by line
  4. Counting the moves without undefined behaviour
  5. Without recursion, from the bits
  6. The same algorithm in other languages
  7. Frequently asked questions

The recursive solution, running

Step through the program. The lit line is the one executing, the towers are labelled for the call that is running, and the stack lists every call still waiting to finish.

hanoi(3, 'A', 'C', 'B')

Move 3 disks from A to C.

Nothing is running yet. The first step makes this call.

Step 0 of 43

Call stack

Depth 0 of 4 max

  1. Empty. Nothing has been called yet.

hanoi.c

#include <stdio.h>

void hanoi(int n, char source, char target, char spare) {
    if (n == 0) {
        return;
    }
    hanoi(n - 1, source, spare, target);
    printf("Move disk %d from %c to %c\n", n, source, target);
    hanoi(n - 1, spare, target, source);
}

int main(void) {
    hanoi(3, 'A', 'C', 'B');
    return 0;
}

Moves

7 in all

Choose a row to jump the program to that move.

Every move the program makes for 3 disks
MoveDiskFromTo
11AC
22AB
31CB
43AC
51BA
62BC
71AC

Run it yourself

Save the listing as hanoi.c and run it:

Run it

gcc hanoi.c -o hanoi
./hanoi

It prints the seven moves of the three-disk puzzle:

Output

Move disk 1 from A to C
Move disk 2 from A to B
Move disk 1 from C to B
Move disk 3 from A to C
Move disk 1 from B to A
Move disk 2 from B to C
Move disk 1 from A to C

Change the 3 in the call to solve a bigger puzzle. Every disk you add doubles the output, plus one line.

Line by line

Not what each line says — the listing says that — but why it has to be there:

LineWhy it is there
1C has no built-in output: printf is an ordinary library function, and stdio.h is where it is declared. C99 removed the old rule that let an undeclared function be called anyway — GCC 13 still only warns, but GCC 14 and current Clang refuse to compile the program without this line.
3Returns void because there is nothing to hand back: the answer to this problem is 2ⁿ − 1 lines of output, and each call prints its own as it goes. The towers are chars, which is all a one-letter name needs.
4–6Recursion needs a size it can answer without calling itself, or nothing ever ends. Zero disks is that size — no disk to move, so return at once. Every chain of calls in the program, however deep, finishes here.
7Disk n is going to target, so the n - 1 disks above it cannot go there too. They go to spare, which is why the last two arguments swap places: this call's spare is that call's target. C passes arguments by value, so the swap happens in copies inside the new call's own stack frame — this call's target is untouched, and line 8 still prints it.
8The only line that moves anything, and legal only because line 7 has just cleared every smaller disk off the source and the target both. %d formats the disk number and %c each tower's letter.
9Line 7 in reverse: the disks are on spare now, so it is the source, and the tower they came from holds nothing smaller than n and becomes the working space.
12–15main starts the program with three disks from A to C. return 0 is how a C program reports success to whatever ran it; the puzzle has no opinion about it.

Why those three lines are enough — the correctness proof, the recurrence and the complexity — is on the Tower of Hanoi algorithm page, and holds for every language here.

Counting the moves without undefined behaviour

count_moves.c

#include <inttypes.h>
#include <stdio.h>

/* 2^n - 1 for 1 <= n <= 64. Writing (1 << 64) - 1 would be undefined
   behaviour, so start from all 64 bits set and shift the surplus away. */
uint64_t minimum_moves(int n) {
    return UINT64_MAX >> (64 - n);
}

int main(void) {
    int sizes[] = {3, 10, 64};
    for (int i = 0; i < 3; i++) {
        printf("%d disks: %" PRIu64 " moves\n", sizes[i], minimum_moves(sizes[i]));
    }
    return 0;
}

Run it

gcc count_moves.c -o count_moves
./count_moves

Output

3 disks: 7 moves
10 disks: 1023 moves
64 disks: 18446744073709551615 moves

2⁶⁴ − 1 fits a uint64_t exactly: it is UINT64_MAX, every one of the 64 bits set. The obvious way to compute it, (UINT64_C(1) << 64) - 1, is not merely wrong in C but undefined. Shifting a value by as many bits as its type has, or more, is undefined behaviour, which means the standard places no requirement on what the program does — and an optimising compiler is entitled to assume it never happens. C++ can turn this exact mistake into a compile error, when the expression is a constant one.

The same trap is much closer than sixty-four disks. With a 32-bit int, 1 << 31 already shifts a bit into the sign position, and that is undefined too. So (1 << n) - 1, the formula in most C tutorials, stops being a correct program at thirty-one disks.

The listing sidesteps both. 2ⁿ − 1 is just the lowest n bits set, so it starts from all 64 bits set and shifts the surplus away: UINT64_MAX >> (64 - n) is valid for every n from 1 to 64. PRIu64, from inttypes.h, expands to whatever format string prints a uint64_t on the platform at hand.

Without recursion, from the bits

hanoi_bits.c

#include <stdio.h>

/* No recursion and no towers in memory: every move of the optimal
   solution can be read straight off the binary digits of its number. */
void hanoi_bits(int n) {
    const char *names = n % 2 == 1 ? "ABC" : "ACB";
    unsigned long long total = (1ULL << n) - 1;

    for (unsigned long long m = 1; m <= total; m++) {
        int disk = 1;
        for (unsigned long long bits = m; (bits & 1) == 0; bits >>= 1) {
            disk++;
        }
        int from = (int)((m & (m - 1)) % 3);
        int to = (int)(((m | (m - 1)) + 1) % 3);
        printf("Move disk %d from %c to %c\n", disk, names[from], names[to]);
    }
}

int main(void) {
    hanoi_bits(3);
    return 0;
}

Run it

gcc hanoi_bits.c -o hanoi_bits
./hanoi_bits

This loop stores no towers and makes no recursive calls: move m is read straight off the binary digits of m. For move m:

  • Disk: one more than the number of trailing zero bits of m.
  • Source tower: (m & (m - 1)) % 3
  • Destination tower: ((m | (m - 1)) + 1) % 3

The towers come out as numbers 0 to 2, which name A, B and C for an odd number of disks and A, C and B for an even number, because the smallest disk circles the other way. Why a binary counter describes the puzzle so exactly is the subject of Tower of Hanoi and binary.

The inner loop counts the trailing zeros one bit at a time to stay portable. GCC and Clang can do it in one instruction with __builtin_ctzll, and C23 standardises the operation as stdc_trailing_zeros in stdbit.h. The shift in (1ULL << n) - 1 is safe here up to 63 disks — for 64 the loop bound would need the UINT64_MAX form from above.

The same algorithm in other languages

Frequently asked questions

How do you write Tower of Hanoi in C?

With a recursive function taking the disk count and three char tower names: if n is 0, return; otherwise call hanoi(n - 1, source, spare, target), printf the move of disk n, and call hanoi(n - 1, spare, target, source). Calling hanoi(3, 'A', 'C', 'B') from main prints the seven moves.

What type holds the Tower of Hanoi move count for 64 disks in C?

uint64_t from stdint.h. 2⁶⁴ − 1 is exactly UINT64_MAX, the largest value it holds. Do not compute it as (1 << 64) - 1: shifting a 64-bit value by 64 is undefined behaviour in C. UINT64_MAX >> (64 - n) gives 2ⁿ − 1 safely for every n from 1 to 64.

Can Tower of Hanoi be solved in C without recursion?

Yes, with one loop and no arrays. For move m, the disk is one more than the number of trailing zero bits in m, the source tower is (m & (m - 1)) % 3 and the destination is ((m | (m - 1)) + 1) % 3, where towers 0, 1 and 2 are A, B and C for an odd number of disks and A, C and B for an even number.