别再自己写轮子了!C++标准库的to_string和stoi函数,处理字符串与数字转换的保姆级教程
C++字符串与数字转换实战:to_string与stoi的高效应用指南
在算法竞赛和日常开发中,字符串与数字之间的转换是最基础却又最频繁的操作之一。许多C++开发者,尤其是刚接触LeetCode等算法平台的初学者,常常会手动实现这些转换逻辑——这不仅浪费时间,还容易引入边界错误。实际上,C++标准库早已为我们准备了成熟高效的解决方案: to_string 和 stoi 系列函数。
1. 为什么应该使用标准库而非手动实现?
手动实现数字与字符串转换是许多C++学习者的第一个"轮子"。一个简单的整数转字符串可能这样写:
string intToString(int num) {
if (num == 0) return "0";
bool isNegative = num < 0;
num = abs(num);
string result;
while (num > 0) {
result = char(num % 10 + '0') + result;
num /= 10;
}
if (isNegative) result = "-" + result;
return result;
}
这段代码看似简单,却隐藏着多个陷阱:
- 未处理INT_MIN的绝对值溢出问题
- 频繁字符串拼接导致性能低下
- 缺乏对异常输入的处理
相比之下,标准库的 to_string 只需一行代码:
string s = to_string(12345); // "12345"
性能对比测试结果 (100万次转换,单位:ms):
| 方法 | 整型转字符串 | 字符串转整型 |
|---|---|---|
| 手动实现 | 125 | 98 |
| 标准库 | 32 | 41 |
标准库实现通常有编译器级别的优化,且经过严格测试,无论在性能还是稳定性上都远超大多数手动实现。
2. to_string:数字转字符串的瑞士军刀
to_string 是定义在 <string> 头文件中的一组重载函数,支持几乎所有内置数字类型的转换:
string to_string(int val);
string to_string(long val);
string to_string(long long val);
string to_string(unsigned val);
string to_string(unsigned long val);
string to_string(unsigned long long val);
string to_string(float val);
string to_string(double val);
string to_string(long double val);
2.1 基础用法与注意事项
int i = 42;
double d = 3.14159;
string s1 = to_string(i); // "42"
string s2 = to_string(d); // "3.141590"
注意:浮点数转换会保留默认精度(通常是6位),可能需要配合
std::setprecision使用
常见问题解决方案 :
- 精度控制 :先使用
ostringstream格式化
double pi = 3.141592653589793;
ostringstream oss;
oss << fixed << setprecision(12) << pi;
string s = oss.str(); // "3.141592653590"
- 区域设置问题 :某些地区使用逗号作为小数点
#include <locale>
setlocale(LC_ALL, "C"); // 强制使用点号作为小数点
2.2 进阶应用:类型组合转换
在模板编程中, to_string 可以与 type_traits 结合实现通用转换:
template<typename T>
enable_if_t<is_arithmetic_v<T>, string> toString(T value) {
return to_string(value);
}
template<typename T>
enable_if_t<!is_arithmetic_v<T>, string> toString(const T& obj) {
ostringstream oss;
oss << obj;
return oss.str();
}
3. stoi系列:字符串解析的强大工具集
与 to_string 对应,C++提供了多个字符串转数字的函数:
| 函数 | 返回类型 | 说明 |
|---|---|---|
| stoi | int | 字符串转整型 |
| stol | long | 字符串转长整型 |
| stoul | unsigned long | 字符串转无符号长整型 |
| stoll | long long | 字符串转长长整型 |
| stoull | unsigned long long | 字符串转无符号长长整型 |
| stof | float | 字符串转浮点数 |
| stod | double | 字符串转双精度浮点数 |
| stold | long double | 字符串扩展精度浮点数 |
3.1 stoi的核心参数解析
完整函数签名:
int stoi(const string& str, size_t* idx = 0, int base = 10);
str:要转换的字符串idx:可选参数,存储第一个未转换字符的位置base:进制(2-36),默认为10进制
多进制转换示例 :
cout << stoi("1010", nullptr, 2); // 二进制 → 10
cout << stoi("FF", nullptr, 16); // 十六进制 → 255
cout << stoi("075", nullptr, 8); // 八进制 → 61
cout << stoi("42", nullptr, 10); // 十进制 → 42
3.2 错误处理与边界情况
stoi 在遇到以下情况时会抛出 invalid_argument 或 out_of_range 异常:
- 无效输入 :
try {
int i = stoi("123abc"); // 转换成功,i=123
int j = stoi("abc123"); // 抛出invalid_argument
} catch (const exception& e) {
cerr << "Error: " << e.what() << endl;
}
- 溢出检测 :
string max_int = to_string(numeric_limits<int>::max());
string overflow = max_int + "0"; // 超出int范围
try {
int i = stoi(overflow); // 抛出out_of_range
} catch (...) {
// 处理溢出
}
安全转换的最佳实践 :
optional<int> safeStoi(const string& s) {
try {
size_t pos;
int val = stoi(s, &pos);
if (pos == s.size()) return val;
} catch (...) {}
return nullopt;
}
4. 算法竞赛中的实战技巧
4.1 LeetCode高频应用模式
模式1:数字各位处理
// 判断回文数
bool isPalindrome(int x) {
if (x < 0) return false;
string s = to_string(x);
return equal(s.begin(), s.end(), s.rbegin());
}
模式2:大数运算模拟
// 字符串相加
string addStrings(string num1, string num2) {
int i = num1.size()-1, j = num2.size()-1;
int carry = 0;
string res;
while (i >= 0 || j >= 0 || carry) {
int n1 = i >= 0 ? num1[i--]-'0' : 0;
int n2 = j >= 0 ? num2[j--]-'0' : 0;
int sum = n1 + n2 + carry;
res.push_back(sum % 10 + '0');
carry = sum / 10;
}
reverse(res.begin(), res.end());
return res;
}
4.2 性能优化策略
虽然 to_string 和 stoi 很方便,但在性能关键路径上可能需要替代方案:
方案对比表 :
| 场景 | 推荐方法 | 示例 | 优势 |
|---|---|---|---|
| 单次转换 | to_string/stoi | stoi("42") |
简洁安全 |
| 批量转换 | sscanf/sprintf | sscanf(str, "%d", &num) |
更快 |
| 极致性能 | 手写优化版本 | 查表法 | 无动态分配 |
快速字符串转整型实现 :
int fastAtoi(const char* str) {
int sign = 1, num = 0;
while (*str == ' ') str++;
if (*str == '-') { sign = -1; str++; }
while (*str >= '0' && *str <= '9') {
num = num * 10 + (*str - '0');
str++;
}
return sign * num;
}
5. 现代C++的扩展与替代方案
C++17引入了 std::from_chars 和 std::to_chars ,提供更安全高效的底层转换:
#include <charconv>
// 字符串转整型
int fromCharsDemo(string_view str) {
int value;
auto [ptr, ec] = from_chars(str.data(), str.data()+str.size(), value);
if (ec == errc()) return value;
throw runtime_error("转换失败");
}
// 整型转字符串
string toCharsDemo(int value) {
char buffer[20];
auto [ptr, ec] = to_chars(buffer, buffer+sizeof(buffer), value);
if (ec == errc()) return string(buffer, ptr);
throw runtime_error("转换失败");
}
对比传统方法优势 :
- 不依赖区域设置
- 无内存分配(对于
to_chars) - 更精确的错误处理
- 支持自定义格式
在实际项目中,当需要处理大量数据转换或对性能有严格要求时,这些新接口是更好的选择。
更多推荐
所有评论(0)