C++ int 与 string 互转

在 C++ 中,整数 123 和字符串 "123" 虽然打印到屏幕上看起来一模一样,但它们的底层类型与运算规则完全不同。整数做 + 运算是数学加法,而字符串做 + 运算则是把两段文本首尾拼在一起,比如下面这段代码:

int num = 123;
std::cout << num + 1 << '\n';      // 整数相加:输出 124

std::string str = "123";
std::cout << str + "1" << '\n';    // 字符串拼接:输出 1231

由于数值与文本的存储格式完全不同,我们不能使用 static_cast 直接转换它们,而是借助 <string> 头文件中的 2 个标准函数:调用 std::to_string() 将整数转为字符串,调用 std::stoi() 将字符串解析为整数。

int 转 string:std::to_string()

在 C++ 中,想要把 int 整数转换为 std::string 字符串,最直接的方式就是调用 <string> 头文件中的 std::to_string() 函数。

语法:

std::to_string(整数)

说明:

std::to_string() 会将传入的整数按十进制格式转换成一个新的 std::string 字符串并返回。除了 int 之外,它也直接支持 long、long long、unsigned int 等其他整数类型。

示例 1:整数转为 string

#include <iostream>
#include <string>

int main() {
    int orderId = 2026;
    std::string text = std::to_string(orderId);

    std::cout << text << '\n';
    std::cout << "订单编号:ID-" << text << '\n';
    return 0;
}

运行结果如下。

2026
订单编号:ID-2026

分析:

在这个例子中,我们调用 std::to_string(orderId) 后,整数 2026 被转换成了字符串 "2026",随后就能拼在 "订单编号:ID-" 后面一起输出。

这里小伙伴们要注意,平时做字符串拼接时,C++ 不支持直接用 + 号把 std::string 和 int 整数相加。下面这种省掉转换步骤的写法就是错误的,编译阶段会直接报错。

int id = 2026;
std::string prefix = "ID-";
std::string wrongStr = prefix + id;    // 报错:不能直接相加

string 转 int:std::stoi()

反过来,如果我们手里拿到的是数字字符串,希望转换成真正的 int 整数参与计算,可以使用 <string> 头文件中的 std::stoi() 函数。其中,stoi 是英文 “string to integer(字符串转整数)” 的缩写。

1. 基本用法

在日常十进制转换中,我们直接把 std::string 字符串传给 std::stoi() 即可。

语法:

std::stoi(字符串)

说明:

std::stoi() 会自动跳过字符串开头可能存在的空格,然后将后面的十进制数字文本解析为 int 整数并返回,正数和负数(如 "-45")都可以正常识别。

示例 2:字符串解析为 int

#include <iostream>
#include <string>

int main() {
    std::string text = "128";
    int count = std::stoi(text);

    std::cout << count << '\n';
    std::cout << count + 2 << '\n';
    return 0;
}

运行结果如下。

128
130

分析:

std::stoi(text) 表示将字符串 "128" 解析为 int 整数 128 并赋值给变量 count。转换完成后,后面的 count + 2 执行的就是整数加法,得到结果 130。

除了转成 int 的 std::stoi() 之外,如果字符串里的整数非常大、超出了 int 的取值范围(约 ±21 亿),<string> 头文件中还提供了同一系列的其他转换函数,如下表所示。

字符串转整数函数
函数名 返回类型 说明
std::stoi() int 最常用,转换为普通有符号整型
std::stol() long 转换为长整型
std::stoll() long long 转换为超长整型,适合超过 21 亿的大整数
std::stoul() unsigned long 转换为无符号长整型

2. 部分解析与停止位置

std::stoi() 有一个很实用的特点:它并不要求整串文本全部都是数字。只要字符串开头是合法的整数,当往后读到字母、小数点或其他符号时,它就会停下来,把前面已经读到的整数返回给我们。

比如调用 std::stoi("120px") 会返回整数 120,调用 std::stoi("3.14") 会在遇到小数点 '.' 时停下并返回整数 3。如果我们还想知道它到底读到了哪个下标位置才停下,可以传入第 2 个参数。

语法:

std::stoi(字符串, 停止位置指针)

说明:

其中,第 2 个参数是 std::size_t* 类型的指针,用来记录停止解析的字符下标。std::size_t 是标准库中专门表示长度与下标的无符号整数类型。

因为函数返回值已经用来返回转出的整数了,所以我们先定义变量 pos,再传入地址 &pos 让函数把停止下标写进去。平时不关心停止位置时,直接省略第 2 个参数即可。

示例 3:获取停止解析的位置

#include <iostream>
#include <string>

int main() {
    std::string width = "120px";
    std::size_t pos = 0;

    int num = std::stoi(width, &pos);

    std::cout << num << '\n';
    std::cout << pos << '\n';
    std::cout << width.substr(pos) << '\n';
    return 0;
}

运行结果如下。

120
3
px

分析:

字符串 "120px" 开头的数字 120 占了 3 个字符(下标 0、1、2),解析在字符 'p' 所在的下标 3 处停下,因此变量 pos 的值被更新为 3。接着我们调用前面学过的 substr() 函数从下标 3 开始截取,就能拿到剩余的单位 "px"。

如果业务场景要求 “整串文本必须完全是纯数字,不能带有任何多余后缀”,我们可以在转换后检查 pos == width.size() 是否成立,如下所示:

std::size_t pos = 0;
int num = std::stoi(width, &pos);
if (pos != width.size()) {
    // 包含未解析的后缀字符
}

3. 指定进制转换

std::stoi() 默认按照十进制来解析字符串,同时还支持通过第 3 个参数指定进制,方便我们把二进制或十六进制字符串直接转成十进制 int 整数。

语法:

std::stoi(字符串, 停止位置指针, 进制)

说明:

第 3 个参数是一个整数,用来指定按多少进制解析,默认值为 10,常用的还有 2(二进制)、8(八进制)和 16(十六进制)。如果当前只想指定进制、不需要记录停止解析的位置,把第 2 个指针参数传为 nullptr 占位即可。

示例 4:解析不同进制字符串

#include <iostream>
#include <string>

int main() {
    // 按二进制解析
    int binVal = std::stoi("1010", nullptr, 2);

    // 按十六进制解析
    int hexVal = std::stoi("FF", nullptr, 16);

    std::cout << binVal << '\n';
    std::cout << hexVal << '\n';
    return 0;
}

运行结果如下。

10
255

分析:

"1010" 按二进制解析后对应的十进制整数是 10,"FF"(或 "0xFF")按十六进制解析后对应的十进制整数是 255。参数中间的 nullptr 表示不记录停止解析的下标位置。

转换失败的异常处理

如果传给 std::stoi() 的字符串开头根本没有数字(比如 "hello"),函数会不会返回 0 呢?

实际上并不会。因为 0 本身就是一个完全合法的转换结果,比如 std::stoi("0") 返回的就是 0。如果转换失败也返回 0,程序就分不清到底是 “成功转出了整数 0” 还是 “转换失败了”。

因此,当 std::stoi() 转换失败时,会直接抛出 <stdexcept> 头文件中的以下 2 种标准异常:

  • std::invalid_argument:当传入 "hello" 或空字符串 "" 等开头没有任何有效整数的文本时,抛出该异常。
  • std::out_of_range:当字符串虽然是合法整数,但数值超出了 int 类型能表示的范围时,抛出该异常。

示例 5:捕获转换失败的异常

#include <iostream>
#include <stdexcept>    // 提供标准异常类
#include <string>

void parseNumber(const std::string& text) {
    try {
        int num = std::stoi(text);
        std::cout << num << '\n';
    } catch (const std::invalid_argument&) {
        std::cout << text << ":不是有效整数" << '\n';
    } catch (const std::out_of_range&) {
        std::cout << text << ":超出 int 范围" << '\n';
    }
}

int main() {
    parseNumber("hello");
    parseNumber("99999999999999999999");
    return 0;
}

运行结果如下。

hello:不是有效整数
99999999999999999999:超出 int 范围

分析:

为了方便连续测试两组非法文本,这里我们定义了一个辅助函数 parseNumber(),并在函数内部使用 try...catch 捕获 std::stoi() 抛出的异常。

当我们第 1 次调用并传入 "hello" 时,由于首字符就无法解析出整数,程序触发了 std::invalid_argument 异常。当我们第 2 次传入超长数字字符串时,数值超出了 int 的取值上限,于是触发了 std::out_of_range 异常。

在实际开发中,只要待转换的字符串来自用户输入或外部文件,我们都建议像这样加上异常捕获,避免程序因为输入格式有误而直接异常终止。

常见问题

1. C++ 中还能使用 C 语言的 atoi() 函数把字符串转成整数吗?

可以使用,但在现代 C++ 开发中并不推荐,小伙伴们平时优先使用 std::stoi() 即可,主要有以下 2 个原因:

参数传递更方便:std::stoi() 可以直接接收 std::string 对象,而 <cstdlib> 中的 atoi() 只接收 const char* 指针,每次调用还要多写一次 .c_str()。

错误更容易排查:传入 "abc" 这类非法文本时,atoi() 不会报错,而是静默返回 0,导致无法区分 "0" 和转换失败。而 std::stoi() 会明确抛出异常,方便大家及时定位问题。

2. std::to_string() 可以把整数转换成十六进制或二进制字符串吗?

不能。std::to_string() 固定只按十进制格式生成字符串,没有提供指定进制的参数。如果需要将整数格式化为十六进制或二进制字符串,我们可以使用后面将要学习的 std::format() 函数。

给站长反馈

绿叶网正在不断完善中,小伙伴们如果发现任何问题,还望多多给站长反馈,谢谢!

邮箱:lvyenet@vip.qq.com

「绿叶网」服务号
绿叶网服务号放大
关注服务号,微信也能看教程。
绿叶网服务号