C语言输入校验:用 strtol 拒绝尾随字符和越界值
从文本中解析分钟数,检查数字格式、尾随字符、数值范围和业务上限,确保失败调用不会意外覆盖输出参数。
本节目标
从文本中解析分钟数,检查数字格式、尾随字符、数值范围和业务上限,确保失败调用不会意外覆盖输出参数。
环境与运行方法
准备支持 C17 的 Clang 或 GCC。保存为 lesson.c,执行 cc -std=c17 -Wall -Wextra -Werror lesson.c -o lesson,编译后执行 ./lesson。命令适用于 macOS/Linux;Windows 需要相应的 C 工具链。
核心思路
atoi 不便区分有效零与失败。strtol 提供结束指针,数值超范围时还会设置 errno。先完成全部验证,再写入调用者的输出参数,可以保留失败前的状态。
完整示例
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <stdbool.h>
bool parse_minutes(const char *text, int *out) {
char *end;
errno = 0;
long value = strtol(text, &end, 10);
if (end == text || *end != '\0' || errno == ERANGE || value < 0 || value > 1440)
return false;
*out = (int)value;
return true;
}
int main(void) {
const char *samples[] = {"45", "12x", "1441", ""};
for (size_t i = 0; i < 4; ++i) {
int minutes = -1;
if (parse_minutes(samples[i], &minutes)) printf("ok=%d\n", minutes);
else printf("invalid=%d\n", minutes);
}
}预期输出
ok=45
invalid=-1
invalid=-1
invalid=-1逐步理解
每次转换前清零 errno,避免先前的错误影响本次判断。end==text 表示没有读取到数字,检查字符串终止符则保证 12x 不会被当作 12。范围限制使最后转成 int 的值处于安全的小范围。
本函数要求两个指针都有效,不接收 NULL。strtol 允许前导空白,本例却拒绝尾随空白;如果要接受两侧空白,需要主动增加规则,而不是依赖偶然的解析行为。
常见问题与边界
- 只检查结果是否为零会拒绝合法零。
- 忽略结束指针会接受部分解析。
- 在检查前写入 out 会让失败也产生副作用。
动手练习
测试 "0"、"1440" 与 "45 "。
参考答案
前两项返回合法值;最后一项的结束字符为空格,因此失败,输出参数仍为原值。是否接受尾随空白应由业务契约决定。
文章回复
0 条公开回复