Trouble implementing a recursive call in C

℡╲_俬逩灬. 提交于 2020-03-28 03:30:21

问题


So I'm I've been working with C for the very first time, and I think I'm having trouble using recursion. For instance, to return a value for a recursive call in C#, I might use return methodRecursiveCall(parameter). In C, I have this statement, which is a part of a roman numeral converter:

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;
}

My question specifically is about the convert(&(s[index]));, which is meant to be a recursive call. It is meant to convert an entire Roman numeral to decimal, however it only converts the first character. That is normally where I would put a 'return'. I'm not sure how to pull this off in C, however.


回答1:


For this fragment from near the end:

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

You probably want something like:

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

You know that the M maps to 1,000; the total value will be 1000 + the value of what follows the M, which is what the expression states. Note that the parentheses around s[index+1] are not necessary.

You'll need to make similar changes throughout the code. You also need to review why you have iteration mixed in with recursion; you should use one or the other.

Note that your code doesn't seem to cover L aka 50.

Personally, I think this is not the best way to do the conversion. All else apart, it will be hard to spot that MXMC is invalid. My code uses an array of structures containing a string and the corresponding value (M and 1000; CM and 900) etc, and once one of the values has been used up (CM can only be used once; M can be used multiple times; CD can be used once; C can be used multiple times — that's coded too), then it can't appear again later. And it uses iteration rather than recursion.


Here's a moderately simple adaptation and fix to your code. It works OK for converting 'known to be valid' Roman numbers; it doesn't work well for validating them.

#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;
}

Sample output:

== 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

Note that the last 'number' is horribly bogus (1000 + 500 + 900 + 1000 + 100 + 100 + 50 + 10 + 1 + 1 + 1 + 1 + 1 + 1).



来源:https://stackoverflow.com/questions/28219838/trouble-implementing-a-recursive-call-in-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!