将罗马数字转换为阿拉伯数字再转换为罗马数字的程序有时会给出错误的结果

Program that converts from roman numerals to arabic numerals to roman sometimes gives wrong result

我有这个程序试图将阿拉伯数字转换为罗马数字,并且编译没有问题,但对于某些值,它给出了正确的答案,但对于其他情况,它没有。例如:

11 是错误的(一个 X 留在 X 的左边) 12 是错误的(一个 X 留在 X 的左边)

20个就好

22 错了(剩下 2 X)

30个就好

32 错了(剩下 2 X)

40个就好

45不好(还剩一个XL) 48 是错误的(一个 X 留在第二个 L 之前)

50个就好

51给坏(剩下一个L) 58 不好(剩下一个 L)

60就好了

char *a2roman (int valor, char *c1, char *c2, char *c3);

int main (void)
{
    int ArabicNumber = 1;
    int result;
    char roman[15] = "";

    do
    {
        printf ("Enter an integer in the range 1 to 3000: \n\t");

        scanf ("%d", &ArabicNumber);
    }
    while ((ArabicNumber < 1) || (ArabicNumber > 3000));

    if ((ArabicNumber <= 3000) && (ArabicNumber >= 1000))
    {
        result = ArabicNumber / 1000;
        strcat (roman, a2roman(result, "M", " ", " "));
        ArabicNumber -= (result * 1000);
    }

    if ((ArabicNumber < 1000) && (ArabicNumber >= 100))
    {
        result = ArabicNumber / 100;
        strcat (roman, a2roman(result, "C", "D", "M"));
        ArabicNumber -= (result * 100);
    }

    if ((ArabicNumber < 100) && (ArabicNumber >= 10))
    {
        result = ArabicNumber / 10;
        strcat (roman, a2roman(result, "X", "L", "C"));
        ArabicNumber -= (result * 10);
    }

    if ((ArabicNumber < 10) && (ArabicNumber >= 1))
    {
        strcat (roman, a2roman(ArabicNumber, "I", "V", "X"));
    }

    printf ("The Roman numeral is: \n\t%s\n\n", roman);
    printf ("\t\t...Press any key to finish.");
    getch();

    return 0;
}

char *a2roman (int value, char *c1, char *c2, char *c3)
{
    int i;
    static char rRoman[15] = "";

    /* Si "valor" = 1, 2, 3 */
    if ((value >= 1) && (value <= 3))
    {
        for (i = 0; i < value; i++)
            strcat (rRoman, c1);
    }

    /* Si "valor" = 5, 6, 7, 8 */
    if ((value >= 5) && (value <= 8))
    {
        strcat (rRoman, c2);

        for (i = 0; i < (value - 5); i++)
            strcat (rRoman, c1);
    }

    /* Si "valor" = 4 */
    if (value == 4)
    {
        strcat (rRoman, c1);
        strcat (rRoman, c2);
    }

    /* Si "valor" = 9 */
    if (value == 9)
    {
        strcat (rRoman, c1);
        strcat (rRoman, c3);
    }

    return (rRoman);
}

a2roman 中的静态缓冲区构建了完整的结果,但每次从 main 调用它时,部分结果也会连接到打印出的缓冲区,因此如果 a2roman 被多次调用。

一个解决方案是在通过使 roman 成为指针并分配 return 值来构建完整结果之后直接使用 a2roman 中的 return 值从 a2roman 到它每次 a2roman 被称为:

char* roman = NULL;
...
roman = a2roman(result, "M", " ", " ");
...
roman = a2roman(result, "C", "D", "M");
...
printf ("The Roman numeral is: \n\t%s\n\n", roman);

但是,如果您想要转换多个数字,由于静态缓冲区,您仍然会遇到问题。如果你有指向它的指针,你可以在数字之间清除它,比如 *roman = 0; 但这对我来说仍然感觉很乱。

另一种解决方案是传入要在其中构造数字的缓冲区。

以下示例展示了如何执行此操作,并且还清理了一些用于将数字分解为数字的逻辑。你的方法有效,但我想我还不如展示另一种方法并节省几行。

#include <stdio.h>
#include <string.h>

void addDigit(char* out, int digit, const char* c1, const char* c2, const char* c3)
{
    if ((digit >= 1) && (digit <= 3))
    {
        for (int i = 0; i < digit; i++)
        {
            strcat(out, c1);
        }
    }

    if ((digit >= 5) && (digit <= 8))
    {
        strcat(out, c2);

        for (int i = 0; i < (digit - 5); i++)
        {
            strcat(out, c1);
        }
    }

    if (digit == 4)
    {
        strcat(out, c1);
        strcat(out, c2);
    }

    if (digit == 9)
    {
        strcat(out, c1);
        strcat(out, c3);
    }
}

void convertNumber(char* out, int num)
{
    if ((num <= 3000) && (num >= 1000))
    {
        addDigit(out, num / 1000, "M", " ", " ");
        num %= 1000;
    }

    if ((num < 1000) && (num >= 100))
    {
        addDigit(out, num / 100, "C", "D", "M");
        num %= 100;
    }

    if ((num < 100) && (num >= 10))
    {
        addDigit(out, num / 10, "X", "L", "C");
        num %= 10;
    }

    if ((num < 10) && (num >= 1))
    {
        addDigit(out, num, "I", "V", "X");
    }
}

int main(void)
{
    for (int i = 1; i < 100; i += 3)
    {
        char buf[32] = { 0 };
        convertNumber(buf, i);
        printf("%4d = %s\n", i, buf);

    }
    for (int i = 101; i < 3000; i += 101)
    {
        char buf[32] = { 0 };
        convertNumber(buf, i);
        printf("%4d = %s\n", i, buf);
    }
    return 0;
}

Online Example

输出:

   1 = I
   4 = IV
   7 = VII
  10 = X
  13 = XIII
  16 = XVI
  19 = XIX
  22 = XXII
  25 = XXV
  28 = XXVIII
  31 = XXXI
  34 = XXXIV
  37 = XXXVII
  40 = XL
  43 = XLIII
  46 = XLVI
  49 = XLIX
  52 = LII
  55 = LV
  58 = LVIII
  61 = LXI
  64 = LXIV
  67 = LXVII
  70 = LXX
  73 = LXXIII
  76 = LXXVI
  79 = LXXIX
  82 = LXXXII
  85 = LXXXV
  88 = LXXXVIII
  91 = XCI
  94 = XCIV
  97 = XCVII
 101 = CI
 202 = CCII
 303 = CCCIII
 404 = CDIV
 505 = DV
 606 = DCVI
 707 = DCCVII
 808 = DCCCVIII
 909 = CMIX
1010 = MX
1111 = MCXI
1212 = MCCXII
1313 = MCCCXIII
1414 = MCDXIV
1515 = MDXV
1616 = MDCXVI
1717 = MDCCXVII
1818 = MDCCCXVIII
1919 = MCMXIX
2020 = MMXX
2121 = MMCXXI
2222 = MMCCXXII
2323 = MMCCCXXIII
2424 = MMCDXXIV
2525 = MMDXXV
2626 = MMDCXXVI
2727 = MMDCCXXVII
2828 = MMDCCCXXVIII
2929 = MMCMXXIX