罗马数字转阿拉伯数字代码在LeetCode报Runtime Error,VS正常求助
问题根源与解决方案
你的代码在LeetCode上触发Runtime Error的核心原因,是误用sizeof(s)获取字符串长度——这是C语言新手极易踩的数组/指针区别坑。
为什么VS里正常,LeetCode里报错?
- 在Visual Studio的代码中,
s是数组类型(char s[] = {'M','C',...}),sizeof(s)会计算整个数组的总字节数,刚好等于罗马数字的字符数7,所以循环逻辑正常。 - 但在LeetCode的函数参数中,
char *s是指针类型,sizeof(s)得到的是当前系统下指针的固定大小(64位系统是8字节,32位是4字节),完全不是字符串的实际长度。
当测试用例"MCMXCIV"有7个字符时,你用指针大小(比如4)作为循环上限nchar,后续循环中会出现两种越界行为:
- 读取
s[4]、s[5]等超出nchar范围的字符 - 往长度为4的
vals数组中写入vals[4]、vals[5]等位置
最终触发AddressSanitizer检测到的heap-buffer-overflow错误。
修正后的代码(保留vals数组版本)
#include <string.h> // 必须包含strlen的头文件 int romanToInt(char * s){ int nchar = strlen(s); // 用strlen获取字符串实际长度 int vals[nchar]; int sum = 0; // 罗马字符转数值,用switch更简洁 for (int i = 0; i < nchar; i++) { switch(s[i]) { case 'I': vals[i] = 1; break; case 'V': vals[i] = 5; break; case 'X': vals[i] = 10; break; case 'L': vals[i] = 50; break; case 'C': vals[i] = 100; break; case 'D': vals[i] = 500; break; case 'M': vals[i] = 1000; break; default: vals[i] = 0; // 处理非法输入,可选 } } // 求和逻辑不变 for (int i = 0; i < nchar; i++) { if (i != nchar - 1 && vals[i] < vals[i + 1]) { sum += vals[i + 1] - vals[i]; i++; } else { sum += vals[i]; } } return sum; }
更高效的优化版本(去掉vals数组)
可以直接在循环中计算数值,省去额外数组的内存开销:
#include <string.h> // 单独提取罗马字符转数值的函数,提升可读性 int getRomanVal(char c) { switch(c) { 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; } } int romanToInt(char * s){ int nchar = strlen(s); int sum = 0; int currentVal, nextVal; for (int i = 0; i < nchar; i++) { currentVal = getRomanVal(s[i]); // 仅当不是最后一个字符时,判断是否需要做减法 if (i < nchar - 1) { nextVal = getRomanVal(s[i+1]); if (currentVal < nextVal) { sum += nextVal - currentVal; i++; // 跳过下一个字符,避免重复计算 continue; } } sum += currentVal; } return sum; }
内容的提问来源于stack exchange,提问作者Rafael Carro Gaudim
相关产品推荐
相关产品推荐

