Software Engineer · 语言与工程基础

C 字符串转整数:完整解析与溢出检查

用 strtol 区分零、非法输入、尾部字符和范围错误,明确 int 目标范围。

题目重点:用 strtol 区分零、非法输入、尾部字符和范围错误,明确 int 目标范围。

题意与假设

这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。

  • 输入是 NUL 结尾字符串;训练合同接受前导空白和符号,不接受尾部非空字符。目标 int 而非任意精度整数。

解题路线

  1. atoi 无法可靠区分合法0与失败,不适合严格校验。strtol 指定 base=10,调用前 errno=0,保存 endptr。
  2. end==start 表示没有数字;errno==ERANGE 表示 long 溢出。结果在 INT_MIN..INT_MAX 外也必须拒绝,因为 long 可能比 int 宽。
  3. 检查尾部是否完全消耗;若允许尾部空白,显式用字符分类逐个跳过,并正确转换 unsigned char。
  4. 成功与值分开返回,避免用特殊整数当错误哨兵。输入长度和底层 locale 行为要纳入接口合同。

手动走一遍

"0" 成功且值0;"abc" 无数字;"12x" 部分解析后按完整合同拒绝。"2147483648" 对常见32位 int 超范围,即便64位 long 可表示,仍不能直接强制转换当成功。

C 参考实现

下面的代码按上文假设实现,适合本地运行并追加自己的测试用例。

代码区可横向滚动;使用键盘时,先聚焦代码区再按方向键查看。

#include <errno.h>
#include <limits.h>
#include <stdlib.h>

/* Accept leading whitespace and a sign; require complete decimal input.
   Caller provides NUL-terminated text and a non-null output pointer. */
int parse_int_decimal(const char *text, int *out) {
    char *end;
    long value;
    if (!text || !out) return 0;
    errno = 0;
    value = strtol(text, &end, 10);
    if (end == text || *end != '\0' || errno == ERANGE ||
        value < INT_MIN || value > INT_MAX) return 0;
    *out = (int)value;
    return 1;
}

复杂度

扫描长度 m 的字符串 O(m),常数额外空间;超长输入先做长度限制以控制资源。

易错点与追问

容易失分的边界

  • errno 不清零导致旧错误。
  • 只检查 long 范围,忽略 int 范围。
  • 允许部分解析却没有告知调用方。

继续深挖

  • 想接受十六进制如何定义前缀与 base?
  • 需要可移植固定32位范围时怎么办?

技术参考

✓已复制微信号!