问题
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