C Program to convert a Roman numeral to its decimal equivalent.

Roman numerals to decimal conversion is a classic algorithm problem that tests your ability to identify the subtractive notation rule. Roman numerals use seven symbols (I, V, X, L, C, D, M) and a key rule: when a smaller value symbol appears before a larger one, it is subtracted instead of added. So IV = 5 − 1 = 4, and IX = 10 − 1 = 9.

The original version of this program used uninitialized pointers (int *a and char *rom with no allocated memory), conio.h, and void main() — it would segfault immediately on any modern system. This rewrite is clean, safe, and compiles with zero warnings under gcc -ansi -Wall -Wextra.

Roman Numeral Symbol Values

Symbol I V X L C D M
Value 1 5 10 50 100 500 1000

The Subtractive Rule

Scan the string from left to right. For each symbol:

  • If the next symbol has a larger value — subtract the current symbol.
  • Otherwise — add the current symbol.

Example: MCMXCIX → M + (−C+M) + (−X+C) + (−I+X) = 1000 + 900 + 90 + 9 = 1999

C Program to Convert Roman Numeral to Decimal

/* Convert Roman numeral to decimal
 * Rule: if current symbol < next symbol, subtract it; otherwise add it.
 * Compile: gcc -ansi -Wall -Wextra roman.c -o roman */
#include <stdio.h>
#include <string.h>

int roman_value(char c)
{
    switch (c) {
        case 'I': return 1;
        case 'V': return 5;
        case 'X': return 10;
        case 'L': return 50;
        case 'C': return 100;
        case 'D': return 500;
        case 'M': return 1000;
        default:  return -1;
    }
}

int roman_to_decimal(const char *roman)
{
    int result = 0;
    int i, cur, next;
    int len = (int)strlen(roman);

    for (i = 0; i < len; i++) {
        cur = roman_value(roman[i]);
        if (cur == -1)
            return -1;          /* invalid character */

        if (i + 1 < len) {
            next = roman_value(roman[i + 1]);
            if (next > cur)
                result -= cur;  /* subtractive: IV=4, IX=9, XL=40, etc. */
            else
                result += cur;
        } else {
            result += cur;      /* last symbol always added */
        }
    }
    return result;
}

int main(void)
{
    char roman[50];
    int decimal;

    printf("Enter a Roman numeral: ");
    scanf("%49s", roman);

    decimal = roman_to_decimal(roman);
    if (decimal == -1)
        printf("Error: invalid Roman numeral character in \"%s\".\n", roman);
    else
        printf("%s = %d\n", roman, decimal);

    return 0;
}

How to Compile and Run

gcc -ansi -Wall -Wextra roman.c -o roman
./roman

Sample Output

Enter a Roman numeral: XIV
XIV = 14

Enter a Roman numeral: IV
IV = 4

Enter a Roman numeral: MCMXCIX
MCMXCIX = 1999

Enter a Roman numeral: MMXXIV
MMXXIV = 2024

Enter a Roman numeral: XYZ
Error: invalid Roman numeral character in "XYZ".

Step-by-Step Trace: MCMXCIX = 1999

i roman[i] cur next Action result
0 M 1000 C=100 next < cur → add 1000 1000
1 C 100 M=1000 next > cur → subtract 100 900
2 M 1000 X=10 next < cur → add 1000 1900
3 X 10 C=100 next > cur → subtract 10 1890
4 C 100 I=1 next < cur → add 100 1990
5 I 1 X=10 next > cur → subtract 1 1989
6 X 10 last symbol → add 10 1999

Common Roman Numeral Equivalents

Roman Decimal Roman Decimal Roman Decimal
I 1 X 10 C 100
IV 4 XL 40 CD 400
V 5 L 50 D 500
IX 9 XC 90 CM 900
XI 11 LX 60 M 1000
XIV 14 XCI 91 MCMXCIX 1999

Code Explanation

  • roman_value() returns −1 for invalid characters — the caller checks for −1 immediately in the loop, allowing clean error reporting. In the original code, unknown characters would silently store garbage into an uninitialized int pointer.
  • The subtractive rule in one if-statementif (next > cur) result -= cur; else result += cur;. Only six valid subtractive combinations exist in standard Roman numerals: IV, IX, XL, XC, CD, CM. The algorithm handles all of them without special-casing each pair.
  • Last symbol: no next to compare — the condition i + 1 < len guards the roman[i+1] access. The last symbol always contributes positively — the loop’s else branch handles it.
  • scanf(“%49s”, roman) — limits input to 49 characters plus the null terminator, preventing buffer overflow. The original used scanf("%s", rom) on an uninitialized pointer — a guaranteed crash or undefined behavior.
  • const char *roman in roman_to_decimal() — the function does not modify the string, so the parameter is const-qualified. This allows passing string literals safely and documents the intent.

What This Program Teaches

  • Left-to-right scanning with lookahead — the algorithm peeks at the next element (roman[i+1]) without advancing i, then decides whether to add or subtract the current one. This lookahead pattern appears in lexers, parsers, and many string algorithms.
  • Switch for character-to-value mapping — a switch statement is faster than a chain of if-else when comparing one variable against a set of constants. The compiler can generate a jump table.
  • Initializing vs. allocating pointers — the original code had int *a with no malloc — a dangling pointer. Arrays with fixed bounds (int a[50] or char roman[50]) are the safe choice when the maximum size is known at compile time.
  • Returning error codes from string functionsroman_to_decimal() returns −1 for invalid input instead of printing an error message itself. Separating parsing from reporting makes the function reusable in larger programs.

Related Programs

Recommended book:
The C Programming Language — Kernighan & Ritchie (India) |
(US)
 | 
C Programming: A Modern Approach — K.N. King (India) |
(US)

Practice what you learned: C Aptitude Questions — or try our C Programming Quiz App on Android.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>