HackerRank数字频率题C代码本地通过但提交报错排查
问题背景
- 题目要求:输入由字母、数字组成的字符串,统计字符串中0-9每个数字的出现频率,按顺序输出0到9的计数,数字之间用空格分隔。
- 故障现象:对应实现的C代码在本地CodeBlocks环境运行能输出预期结果,但提交到判题平台始终返回错误答案。
提交的原始代码
#include <string.h>` #include <math.h> #include <stdlib.h> int main() { char s[1000]; char a[10]={0,0,0,0,0,0,0,0,0,0}; int i; scanf("%[^\n]", s); int l = strlen(s); for(i=0; i<l; i++){ int m = s[i]-48; a[m]=a[m]+1; } for(i=0; i<9; i++){ printf("%d ", a[i]); } printf("%d", a[9]); return 0; }
注意:原始代码中#include <string.h>行尾多了一个多余的反引号,属于手滑输入的语法错误,首先需要删掉。
代码存在的核心问题
- 缺少必要头文件:代码中使用了
scanf、printf标准输入输出函数,但没有引入<stdio.h>头文件。部分本地编译器会做隐式声明兼容,不会立刻报错,但在线判题环境的编译选项更严格,会直接触发编译错误或未定义行为。另外代码中完全没有用到<math.h>、<stdlib.h>的函数,属于冗余引入,不影响运行但无实际作用。 - 未过滤非数字字符,导致数组越界:遍历字符串时,不管当前字符是数字还是字母,都直接减'0'(即代码中写的48)转成数组下标。字母的ASCII码范围是65-90(大写)、97-122(小写),减48之后得到的下标是17-42、49-74,远远超出计数数组
a的0-9下标范围,属于典型的越界写入,会篡改栈上其他变量的内存数据,直接导致计数结果完全错误。本地测试如果用的字符串刚好字母少、内存布局巧合可能看不出问题,但判题平台的标准测试用例一定会包含字母字符,必然触发错误。 - 计数数组类型错误:用
char类型的数组存计数,char在绝大多数环境下是有符号类型,取值范围只有-128~127,如果测试用例中某个数字出现次数超过127,就会发生整数溢出,得到负数或者错误的计数值。计数变量必须用int类型。 - 输入读取存在隐患:
scanf("%[^\n]", s)没有限制最大读入长度,一旦输入字符串长度超过999就会写爆s数组的栈空间,属于缓冲区溢出漏洞;另外如果输入流开头残留换行符,会直接读入空字符串,更稳妥的读入方式是限制长度,或者直接逐字符读入直到遇到EOF/换行。
修正后的可通过代码
#include <stdio.h> #include <string.h> int main() { char s[1000]; int a[10] = {0}; // 计数数组用int类型,初始化全0可只写第一个元素为0,剩余元素编译器自动补0 int i; scanf("%999[^\n]", s); // 限制最大读入长度999,预留字符串结束符位置 int l = strlen(s); for(i = 0; i < l; i++){ // 仅当当前字符是数字时执行计数 if(s[i] >= '0' && s[i] <= '9'){ int m = s[i] - '0'; // 用字符常量'0'代替硬编码48,可读性更好 a[m]++; } } for(i = 0; i < 9; i++){ printf("%d ", a[i]); } printf("%d\n", a[9]); return 0; }
内容的提问来源于stack exchange,提问作者rumon
相关产品推荐
相关产品推荐

