HOWTO · C++

如何在 C++ 中把 Char 数组转换为 Int

本文演示了在 C++ 中把 char 数组转换为 int 类型的方法。

本页内容

以空字符结尾的 char 数组可以存放表示整数的文本。C++ 提供了多种解析这类文本的方法,但它们报告错误的方式不同,也不一定都会拒绝数字前缀后面的其他字符。应根据输入是否可信,以及是否要求整个数组都构成有效数字来选择方法。

示例使用十进制输入。成功解析数字前缀并不一定意味着所有字符都已处理。例如,解析 "23323tail" 可以得到 23323,而 tail 仍未解析。如果要求整个输入都是数字,还要检查解析器停止的位置以及转换结果。

使用 std::strtol 函数将 char 数组转换为 int

std::strtol 会解析以空字符结尾的字符序列,并返回一个 long。第三个参数用于选择数制:十进制使用 10,十六进制使用 16,使用 0 则根据前缀推断数制。除 0 以外,有效数制范围为 2 到 36。

第二个参数接收一个指针,指向第一个未被处理的字符。如果它仍指向输入的开头,就表示没有解析到数字;如果它指向末尾的空字符,就表示整个字符串都已处理。调用函数前将 errno 设为零,并在调用后检查 ERANGE,以检测结果是否超出 long 的范围。由于返回值是 long,存入 int 前还要将它与 std::numeric_limits<int>::min() 和 max() 进行比较。

运行此示例。它使用存放在以空字符结尾的字符数组中的十进制文本,并输出解析得到的整数。

本节中的代码以及显示的标签或输出仍为英文。

#include <cerrno>
#include <cstdlib>
#include <iostream>
#include <limits>

int main() {
  const char input[] = "23323";
  char* end = nullptr;
  errno = 0;
  const long parsed = std::strtol(input, &end, 10);

  if (end == input || *end != '\0' || errno == ERANGE ||
      parsed < std::numeric_limits<int>::min() ||
      parsed > std::numeric_limits<int>::max()) {
    std::cout << "Could not convert the complete input.\n";
    return 0;
  }

  const int value = static_cast<int>(parsed);
  std::cout << value << '\n';
}

提供的成功案例运行结果显示,程序以代码 0 退出,并产生以下输出:

23323

这次运行只覆盖了该有效输入;它不能说明转换失败或数值超出范围时的行为。处理实际输入时应保留这些检查:它们可以分别识别未发生转换、存在未处理字符、超出 long 范围,以及数值无法存入 int 的情况。

使用 std::atoi 函数将 char 数组转换为 int

当输入可信且格式正确时,std::atoi 是一种简洁的选择:

int value = std::atoi(input);

它会接受开头的空白字符和可选的正负号,然后解析十进制数字。和其他前缀解析函数一样,遇到非数字字符时它可以停止解析,并忽略后面的内容。它无法可靠地区分有效的零和转换失败,也不能为范围错误提供有用的错误信息。如果解析出的值无法用 int 表示,行为是未定义的;不要对未经检查或不可信的数字输入使用 std::atoi。如果输入可能格式错误或超出范围,或者调用方需要转换诊断信息和明确的 int 范围检查,请使用 std::strtol。

使用 std::sscanf 函数将 char 数组转换为 int

std::sscanf 会根据格式解析文本,并报告成功转换的项目数。只转换一个整数时,应先确认返回值为 1,再使用目标变量:

int value = 0; int converted = std::sscanf(input, "%d", &value);

%d 会接受开头的空白字符和可选的正负号,然后读取十进制数字。它可能成功解析一个前缀,同时留下未读取的尾随文本;如果要求处理完整输入,可以添加格式检查,或改用其他解析方法。目标参数必须指向一个真实且可写的 int 对象;只有在转换计数确认转换成功后,才能读取它。转换计数并不能保证无法表示的结果是安全的:如果匹配到的值无法用 int 表示,行为是未定义的。对于未经检查或不可信、且可能超出范围的数字输入,不要使用 %d。对于这个简单任务,std::strtol 能更明确地进行停止位置和范围检查。

使用循环将 char 数组转换为 int

当程序需要自定义可接受的语法时,可以使用循环。首先定义该语法。例如,十进制解析器可以接受可选的开头 + 或 -,要求至少有一位数字,并拒绝其他所有字符。每次执行乘法和加法前,还必须检查下一个数字是否会使结果超出选定的整数范围。否则,有符号溢出可能导致结果错误,或引发未定义行为。

不要跳过任意非数字字符,再把后面的数字拼接起来:把 "23tail4" 转成 234 是在筛选字符,并非解析整数。完整的自定义解析器必须处理符号的位置、数字验证、完整输入检查和溢出。除非确实需要这些自定义规则,否则请改用 std::strtol 及其结束位置指针。

总结

一般情况下,优先使用 std::strtol:它会提供停止位置,并能检测 long 范围错误;转换为 int 前,还可以检查结果是否在 int 的范围内。只有当输入可信且格式正确、不需要详细诊断时,才使用 std::atoi。需要按格式解析时,可以选择 std::sscanf,并检查它的转换计数。如果程序需要有意采用不同的输入语法,可以编写循环,并明确实现符号、数字、完整输入和溢出检查。