我目前正在从事一个将罗马数字转换为阿拉伯数字,反之亦然的项目。我还负责实现诸如vinculum之类的概念,其中如果您在罗马数字上方放置一个小节,则下面的数字将乘以1,000。
我遇到的问题是,我只能从一边进行工作,这意味着:我可以不使用Vinculum而从罗马数字转换为阿拉伯语:例如。I = 1,II = 2但是,当这可行时,我的Vinculum代码不起作用。
这是我的代码片段:
int romanToDecimal(char input[], size_t end) {
int roman = 0;
int vroman = 0;
for (int i = 0; i < strlen(input); ++i)
{
int s1 = value(input[i]);
int s2 = value(input[i]);
if (input[i] == '-')
{
for (int j = i - 1; j >= 0; --j)
{
roman = (roman + value(input[j]));
}
roman *= 1000;
for (int k = i + 1; k <= strlen(input); k++)
roman += value(input[k]);
}
else
roman += s1;
}
return roman;
}
我们使用'-'代替字符顶部的栏,因为我们无法在计算机中轻松地做到这一点。因此IV-将是4000,XI-将是11,000,依此类推...
我知道执行循环的方式导致一些被转换的数字相加两次,因为if(input [i] =='-')一次循环遍历字符串中的每个字符。
好的,所以我的问题基本上是使其运作的逻辑是什么?因此,如果字符串包含“-”,它将把数字乘以1000;如果字符串不包含“-”,那么它将照常转换。现在我相信正在发生的事情是,当"if (input[i] == '-')"
为false时,该部分代码仍在运行,当字符串包含'-'时,我怎么不让它完全运行?
发布的代码似乎不完整或至少有一些未使用的变量(例如end
,如果它代表字符串的长度,则可以代替以下重复的变量strlen(input)
)或无意义的s2
变量(例如)。
我不了解您的“ Vinculum”实现背后的逻辑,但简单
roman += s1; // Where s1 = value(input[i]);
解析罗马数字显然是不够的,因为每个符号的相对位置很重要。考虑例如“ IV”为4(= 5-1),而“ VI”为6(= 5 +1)。
要解析“减法”表示法,您可以存储部分结果,并将当前数字与前一个数字进行比较。类似于以下内容:
#include <stdio.h>
#include <string.h>
int value_of(char ch);
long decimal_from_roman(char const *str, size_t length)
{
long number = 0, partial = 0;
int value = 0, last_value = 0;
for (size_t i = 0; i < length; ++i)
{
if (str[i] == '-')
{
number += partial;
number *= 1000;
partial = 0;
continue;
}
last_value = value;
value = value_of(str[i]);
if (value == 0)
{
fprintf(stderr, "Wrong format.\n");
return 0;
}
if (value > last_value)
{
partial = value - partial;
}
else if (value < last_value)
{
number += partial;
partial = value;
}
else
{
partial += value;
}
}
return number + partial;
}
int main(void)
{
char const *tests[] = {
"I", "L", "XXX", "VI", "IV", "XIV", "XXIII-",
"MCM", "MCMXII", "CCXLVI", "DCCLXXXIX", "MMCDXXI", // 1900, 1912, 246, 789, 2421
"CLX", "CCVII", "MIX", "MLXVI" // 160, 207, 1009, 1066
};
int n_samples = sizeof(tests) / sizeof(*tests);
for (int i = 0; i < n_samples; ++i)
{
long number = decimal_from_roman(tests[i], strlen(tests[i]));
printf("%12ld %s\n", number, tests[i]);
}
return 0;
}
int value_of(char ch)
{
switch (ch)
{
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 0;
}
}
请注意,前面的代码仅检查错误的字符,而不丢弃诸如“ MMMMMMMMMMIIIIIIIIIIIIIVIV”之类的字符串。认为这只是一个起点,可以随时进行改进。
嗨,我对CC还是比较陌生。请问sizeof(tests)/ sizeof(* tests)是什么意思?我猜想它得到tests []数组的长度,*是一个指针。在这种情况下,指针到底能做什么?这就是为什么在我的代码中,我并没有真正使用它。但是我知道对于C编程来说这是一个重要的概念。
@JJ
sizeof(tests)/sizeof(*tests)
获取数组中元素的数量。sizeof(tests)
提供tests
以字节为单位的大小。以字节为单位sizeof(*tests)
提供第一个值的大小(并且由于它们都是相同的类型,因此提供任何值的大小)tests
。如果您要编译到最新的C ++标准,则可以使用该std::size
函数来计算元素的数量,而不必大惊小怪。注意,由于数组衰减,这不适用于传递给函数的数组。@JJ我发布了一个C程序,尽管由于您发布的摘录,您的问题蜂也被标记为C ++。如果您最初对C ++感兴趣,请编辑问题以添加该信息。回到您的评论中,是的,我使用该模式“自动”获取了数组的大小,不,如果您还没有学会指针的工作原理,则不必使用它。我本可以显式地使用大小(例如
const char *tests[16] = ...
),然后传递该数字,但是它必须正确(如果决定添加其他测试,则必须更新)或添加NULL终止符作为标记以停止循环。