【问题标题】:Trouble implementing a recursive call in C在 C 中实现递归调用时遇到问题
【发布时间】:2015-01-29 16:34:34
【问题描述】:

所以我是第一次使用 C,我认为我在使用递归时遇到了麻烦。例如,要为 C# 中的递归调用返回一个值,我可能会使用 return methodRecursiveCall(parameter)。在 C 中,我有这个语句,它是罗马数字转换器的一部分:

int convert(char *s)
{    
    int val = 0;
    int index = 0;
    int length = strlen(s);

    while (length >1)
    {

        if (s[index] == 'I')
        {
            if(s[index + 1] == 'V' || s[index + 1] == 'X' || s[index + 1] == 'C' || s[index + 1] == 'D' || s[index + 1] == 'M')
            {
                val--;
                index++;
                length--;
                convert(&(s[index]));
            }
            else
            {
                val++;
                index++;
                length--;
                convert(&(s[index]));
            }
        }

        if (s[index] == 'V')
        {
            if(s[index + 1] == 'X' || s[index + 1] == 'C' || s[index + 1] == 'D' || s[index + 1] == 'M')
            {
                val = val - 5;
                index++;
                length--;
                convert(&(s[index]));
            }
            else
            {
                val = val + 5;
                index++;
                length--;
                convert(&(s[index]));
            }
        }

        if (s[index] == 'X')
        {
            if(s[index + 1] == 'C' || s[index + 1] == 'D' || s[index + 1] == 'M')
            {
                val = val - 10;
                index++;
                length--;
                convert(&(s[index]));
            }
            else
            {
                val = val + 10;
                index++;
                length--;
                convert(&(s[index]));
            }
        }

        if (s[index] == 'C')
        {
            if((s[index + 1]) == 'D' || (s[index + 1]) == 'M')
            {
                val = val - 100;
                index++;
                length--;
                convert(&(s[index]));
            }
            else
            {
                val = val + 100;
                index++;
                length--;
                convert(&(s[index]));
            }
        }

        if (s[index] == 'D')
        {
            if(s[index + 1] == 'M')
            {
                val = val - 500;
                index++;
                length--;
                convert(&(s[index]));
            }
            else
            {
                val = val + 500;
                index++;
                length--;
                convert(&(s[index]));
            }
        }

        if (s[index] == 'M')
        {

            val = val + 500;
            index++;
            length--;
            convert(&(s[index]));

        }    
    }
    return val;
}

我的问题是关于convert(&(s[index]));,它是一个递归调用。它旨在将整个罗马数字转换为十进制,但它只转换第一个字符。这通常是我会“退货”的地方。但是,我不确定如何在 C 中实现这一点。

【问题讨论】:

  • 我看不出在这里使用递归有什么意义。您的函数被赋予一个char* 指针作为参数。为什么不单步执行并使用单个循环处理输入字符串(例如,while (*s) { ... })。另外,尝试使用 switch 语句而不是所有 if 构造。
  • 你似乎忘记了L,又名50。
  • 你可以像在 C# 中那样做。 return convert(&(s[index]));你试过了吗,它是否像你期望的那样工作?我没有检查逻辑错误或任何东西,但这就是返回值的全部内容。您在 C# 中成功尝试过该算法吗?
  • C 中的递归没有什么特别之处。您已经发现了 return 关键字。问题在于这些函数的递归逻辑。内部带有递归的 while 循环似乎很奇怪。而且你在调用convert之后永远不会使用返回的值。
  • 您正在调用 convert 并忽略返回值。你为什么叫它?你预计会发生什么?

标签: c recursion roman-numerals


【解决方案1】:

对于接近尾声的这个片段:

if (s[index] == 'M')
{
    val = val + 500;
    index++;
    length--;
    convert(&(s[index]));
}

你可能想要这样的东西:

if (s[index] == 'M')
    val = 1000 + convert(&s[index+1]);

您知道M 映射到 1,000;总值将是 1000 + M 后面的值,这就是表达式的状态。请注意,s[index+1] 周围的括号不是必需的。

您需要在整个代码中进行类似的更改。您还需要查看为什么将迭代与递归混合在一起;您应该使用其中一个。

请注意,您的代码似乎没有涵盖 L aka 50。

就个人而言,我认为这不是进行转换的最佳方式。除此之外,很难发现MXMC 是无效的。我的代码使用包含字符串和相应值的结构数组(M1000CM 和 900)等,一旦其中一个值用完(CM 只能使用一次; M 可以多次使用;CD 可以使用一次;C 可以多次使用——这也是编码的),以后就不能再出现了。它使用迭代而不是递归。


这是对您的代码的适度简单的修改和修复。它可以很好地转换“已知有效”的罗马数字;它不能很好地验证它们。

#include <stdio.h>

int convert(const char *s);
int convert(const char *s)
{
    int val = 0;
    int i = 0;

    if (s[i] == '\0')
        return 0;

    if (s[i] == 'I')
    {
        if (s[i + 1] != 'I' && s[i + 1] != '\0')
            val = convert(&s[i + 1]) - 1;
        else
            val = 1 + convert(&s[i + 1]);
    }

    if (s[i] == 'V')
        val = 5 + convert(&s[i + 1]);

    if (s[i] == 'X')
    {
        if (s[i + 1] == 'L' || s[i + 1] == 'C' || s[i + 1] == 'D' || s[i + 1] == 'M')
            val = convert(&s[i + 1]) - 10;
        else
            val = 10 + convert(&s[i + 1]);
    }

    if (s[i] == 'L')
        val = 50 + convert(&s[i + 1]);

    if (s[i] == 'C')
    {
        if ((s[i + 1]) == 'D' || (s[i + 1]) == 'M')
            val = convert(&s[i + 1]) - 100;
        else
            val = 100 + convert(&s[i + 1]);
    }

    if (s[i] == 'D')
        val = 500 + convert(&s[i + 1]);

    if (s[i] == 'M')
        val = 1000 + convert(&s[i + 1]);

    return val;
}

int main(void)
{
    const struct roman
    {
        const char *str;
        int num;
    } test[] =
    {
        { "I",                  1 },
        { "II",                 2 },
        { "III",                3 },
        { "IV",                 4 },
        { "V",                  5 },
        { "VI",                 6 },
        { "VII",                7 },
        { "VIII",               8 },
        { "VIIII",              9 },
        { "IX",                 9 },
        { "X",                 10 },
        { "XI",                11 },
        { "XII",               12 },
        { "XIII",              13 },
        { "XIV",               14 },
        { "XV",                15 },
        { "XVI",               16 },
        { "XVII",              17 },
        { "XVIII",             18 },
        { "XIX",               19 },
        { "XVIIII",            19 },
        { "XX",                20 },
        { "XXI",               21 },
        { "XXX",               30 },
        { "XL",                40 },
        { "L",                 50 },
        { "LXXVIII",           78 },
        { "XCVIII",            98 },
        { "IC",                99 },
        { "XCIX",              99 },
        { "C",                100 },
        { "D",                500 },
        { "M",               1000 },
        { "MMMDCCCLXXXVIII", 3888 },
        { "MDCMMCCLXIIIIII", 3666 }, // Not good for validating!
    };
    enum { NUM_TEST = sizeof(test) / sizeof(test[0]) };

    for (int i = 0; i < NUM_TEST; i++)
    {
        int value = convert(test[i].str);
        printf("%s  %15s = %4d vs %4d\n", (value == test[i].num) ? "== PASS ==" : "!! FAIL !!",
               test[i].str, value, test[i].num);
    }
    return 0;
}

样本输出:

== PASS ==                I =    1 vs    1
== PASS ==               II =    2 vs    2
== PASS ==              III =    3 vs    3
== PASS ==               IV =    4 vs    4
== PASS ==                V =    5 vs    5
== PASS ==               VI =    6 vs    6
== PASS ==              VII =    7 vs    7
== PASS ==             VIII =    8 vs    8
== PASS ==            VIIII =    9 vs    9
== PASS ==               IX =    9 vs    9
== PASS ==                X =   10 vs   10
== PASS ==               XI =   11 vs   11
== PASS ==              XII =   12 vs   12
== PASS ==             XIII =   13 vs   13
== PASS ==              XIV =   14 vs   14
== PASS ==               XV =   15 vs   15
== PASS ==              XVI =   16 vs   16
== PASS ==             XVII =   17 vs   17
== PASS ==            XVIII =   18 vs   18
== PASS ==              XIX =   19 vs   19
== PASS ==           XVIIII =   19 vs   19
== PASS ==               XX =   20 vs   20
== PASS ==              XXI =   21 vs   21
== PASS ==              XXX =   30 vs   30
== PASS ==               XL =   40 vs   40
== PASS ==                L =   50 vs   50
== PASS ==          LXXVIII =   78 vs   78
== PASS ==           XCVIII =   98 vs   98
== PASS ==               IC =   99 vs   99
== PASS ==             XCIX =   99 vs   99
== PASS ==                C =  100 vs  100
== PASS ==                D =  500 vs  500
== PASS ==                M = 1000 vs 1000
== PASS ==  MMMDCCCLXXXVIII = 3888 vs 3888
== PASS ==  MDCMMCCLXIIIIII = 3666 vs 3666

请注意,最后一个“数字”是非常虚假的(1000 + 500 + 900 + 1000 + 100 + 100 + 50 + 10 + 1 + 1 + 1 + 1 + 1 + 1)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-12-23
    • 1970-01-01
    • 2020-06-01
    • 1970-01-01
    • 2018-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多