string与数值的相互转换
较难2数字与字符串的变身术:轻松实现互相转换
这个技能是干什么的?
写程序时,我们经常要跟数字和文字打交道。比如:
- 从键盘读入一个成绩“95”,它是一串字符,但你要用它做加法(计算总分),就必须先把它变成真正的数字 95。
- 反过来,你算出了总分 380,想显示在屏幕上“你的总分是380分”,又得把数字 380 变成字符串 "380",才能跟其他文字拼在一起。
简单说:字符串 → 数字 用于计算,数字 → 字符串 用于显示或拼接。这是每个程序员的基本功,就像你会把零花钱的数目写在本子上,也能把本子上的数字读出来算账一样。
一、把数字变成字符串(数值 → 字符串)
生活中的例子
你有一堆硬币:1元、5角、1角……你数出总共 3.6元,然后在作文本上写“我攒了3.6元零花钱”。这个过程就是把数字 3.6 写成了文字 "3.6"。
C++ 做法:to_string()
C++ 从 C++11 开始提供了 std::to_string() 函数,可以轻松把整数、浮点数、长整数等转成 std::string。
int age = 12; // 年龄
double price = 19.95; // 商品价格 19.95 元
string s1 = to_string(age); // 转成字符串 "12"
string s2 = to_string(price); // 转成字符串 "19.950000"
注意浮点数的精度
to_string() 默认只保留 6 位有效数字,而且会自动补零。比如 3.1415926535 转成 "3.141593"(保留 6 位小数)。
如果你想要更精确的格式(比如保留两位小数),就不能用 to_string,而要用 ostringstream 或者 sprintf(后面会提到)。
Python 做法:str()
Python 更简单,用 str() 函数:
age = 12 # 年龄
price = 19.95 # 商品价格
s1 = str(age) # "12"
s2 = str(price) # "19.95" (自动保留原有小数位数)
Python 的 str() 不会像 C++ 那样自动补零,它尽量保留原来的样子,但也会把像 3.1415926535 这种长小数显示为完整精度(过去是保留 12 位左右)。
二、把字符串解析成数字(字符串 → 数值)
生活中的例子
老师发成绩单,上面写的是“95”。你想算全班平均分,就要把这张纸上的“95”当成数字 95 加进去。程序里也一样:从文件或键盘读到的内容是字符串,必须先转成数字才能计算。
C++ 做法:stoi、stod 等函数
C++ 提供了几个以 st 开头的函数(string to integer/float),都放在 <string> 头文件中:
| 函数 | 用途 | 示例 |
|---|---|---|
stoi(str) | 字符串转整型(int) | int n = stoi("456"); |
stol(str) | 转长整型(long) | long n = stol("123456789"); |
stoll(str) | 转长长整型(long long) | long long n = stoll("999999999999"); |
stof(str) | 转单精度浮点(float) | float f = stof("3.14"); |
stod(str) | 转双精度浮点(double) | double d = stod("2.71828"); |
stold(str) | 转长双精度(long double) | long double ld = stold("1.23456789"); |
这些函数会自动忽略字符串开头的空格,但遇到非法字符会停止解析。比如 stoi(" -456abc") 会成功得到 -456,剩下的 “abc” 被丢弃。
进阶用法:stoi 的第二个参数 pos
每个 stox 函数还有一个可选参数 size_t* pos,表示转换结束时读取到的位置(即第一个未被转换的字符下标)。如果你想知道是否整个字符串都被成功转换,可以用它:
string str = "123abc";
size_t pos;
int val = stoi(str, &pos); // val = 123, pos = 3
if (pos != str.size()) {
cout << "有未转换的字符,位置在 " << pos << endl;
}
第三个参数:指定进制
对于 stoi 和 stol/stoll,还可以传入第三个参数 int base 指定进制(2~36)。比如:
string hexStr = "FF"; // 16进制数
int decimal = stoi(hexStr, nullptr, 16); // 把 "FF" 看作16进制,得到 255
string binStr = "1010";
int binVal = stoi(binStr, nullptr, 2); // 把 "1010" 看作2进制,得到 10
Python 做法:int() 和 float()
Python 的内置函数 int() 和 float() 也能完成同样的工作:
s1 = "123"
s2 = "3.14159"
s3 = " -456 " # 注意有空格
num1 = int(s1) # 123
num2 = float(s2) # 3.14159
num3 = int(s3) # 错误!Python 的 int() 和 float() 不能自动忽略前导/尾随空格
Python 的重要陷阱:不能自动忽略空格!
C++ 的 stoi 会自动忽略前导空格,但 Python 的 int() 和 float() 会直接报 ValueError。你需要先用 strip() 去掉空格:
num3 = int(s3.strip()) # 先去掉空格,再转换,得到 -456
进制转换
Python 的 int() 第二个参数可以指定进制:
hex_str = "FF"
decimal = int(hex_str, 16) # 255
bin_str = "1010"
bin_val = int(bin_str, 2) # 10
三、新手最容易犯的错误(常见陷阱)
1. 忘记处理非法输入
如果字符串不是合法的数字(比如 "abc123"、"12.34.56"、空字符串),转换函数会失败。
- C++:抛出
std::invalid_argument异常;如果数字太大超出范围,抛出std::out_of_range。 - Python:抛出
ValueError。
正确做法:用 try...catch(C++)或 try...except(Python)捕获异常,或者在转换前先判断字符串格式(比如用正则表达式)。
2. 浮点数精度丢失
to_string(3.1415926535) 得到 "3.141593",丢失了后面的小数位。如果你需要保留两位小数,比如价格显示 19.95 而不是 19.950000,不能直接用 to_string。
解决方案:使用字符串流(ostringstream)配合 setprecision,或者直接用 C 风格的 sprintf(C++ 中也兼容)。
C++ 示例(用 ostringstream 控制精度):
#include <sstream>
#include <iomanip>
double price = 19.95;
ostringstream oss;
oss << fixed << setprecision(2) << price; // 保留两位小数
string result = oss.str(); // "19.95"
3. Python 中漏掉 strip() 导致出错
很多初学者习惯像 C++ 那样直接 int(" 45"),结果报错。记住:Python 的 int/float 不接受任意位置的空白,只能用 .strip() 处理前后空格。
4. 混淆 to_string 的精度与 ostringstream
to_string 是快速转换,但不适合需要格式化输出时。而 ostringstream 功能强大,可以控制宽度、填充、进制等,但代码稍长。
5. 忘记包含头文件(C++)
C++ 中使用 stoi、to_string 需要 #include <string>,使用 ostringstream 需要 #include <sstream>。
四、完整可运行的代码示例(C++ + Python 对比)
C++ 完整示例
#include <iostream>
#include <string>
#include <sstream> // 需要 ostringstream
#include <iomanip> // 需要 setprecision
using namespace std;
int main() {
// 1. 数值 → 字符串(普通用法)
int score = 95; // 考试成绩
double price = 19.95; // 价格
string scoreStr = to_string(score); // "95"
string priceStr = to_string(price); // "19.950000"(精度不够好)
cout << "成绩字符串: " << scoreStr << endl;
cout << "价格字符串(不好): " << priceStr << endl;
// 2. 数值 → 字符串(控制格式)
ostringstream oss;
oss << fixed << setprecision(2) << price; // 保留两位小数
string goodPrice = oss.str(); // "19.95"
cout << "价格字符串(好): " << goodPrice << endl;
// 3. 字符串 → 数值(正常情况)
string strAge = "12";
string strGrade = "3.5"; // 平均绩点
int age = stoi(strAge); // 12
double gpa = stod(strGrade); // 3.5
cout << "年龄: " << age << ", 绩点: " << gpa << endl;
// 4. 字符串 → 数值(带前导空格,不含非法字符)
string strNum = " -456 ";
int num = stoi(strNum); // 成功得到 -456
cout << "带空格字符串转整数: " << num << endl;
// 5. 字符串 → 数值(非法输入处理)
string bad = "abc123";
try {
int val = stoi(bad);
cout << "成功转换: " << val << endl;
} catch (const invalid_argument& e) {
cout << "非法输入: " << e.what() << endl;
} catch (const out_of_range& e) {
cout << "数值超出范围: " << e.what() << endl;
}
// 6. 带进制转换
string hexStr = "FF";
int hexVal = stoi(hexStr, nullptr, 16); // 16进制转10进制
cout << hexStr << " (16进制) = " << hexVal << " (10进制)" << endl;
return 0;
}
Python 完整示例
# 1. 数值 → 字符串(普通用法)
score = 95
price = 19.95
score_str = str(score) # "95"
price_str = str(price) # "19.95"
print(f"成绩字符串: {score_str}")
print(f"价格字符串: {price_str}")
# 2. 数值 → 字符串(控制格式,保留两位小数)
# 可以用 format 或 f-string
good_price = f"{price:.2f}" # "19.95"
print(f"价格字符串(两位小数): {good_price}")
# 3. 字符串 → 数值(正常情况)
str_age = "12"
str_grade = "3.5"
age = int(str_age)
gpa = float(str_grade)
print(f"年龄: {age}, 绩点: {gpa}")
# 4. 字符串 → 数值(带空格,必须手动 strip)
str_num = " -456 "
num = int(str_num.strip()) # 去掉前后空格再转换
print(f"带空格字符串转整数: {num}")
# 5. 字符串 → 数值(非法输入处理)
bad = "abc123"
try:
val = int(bad)
print(f"成功转换: {val}")
except ValueError as e:
print(f"非法输入: {e}")
# 6. 带进制转换
hex_str = "FF"
hex_val = int(hex_str, 16) # 16进制转10进制
print(f"{hex_str} (16进制) = {hex_val} (10进制)")
五、总结与相关知识点指引
要点速览
| 操作 | C++ 函数 | Python 函数 | 注意事项 |
|---|---|---|---|
| 整数转字符串 | to_string(int) | str(int) | C++ 浮点数精度有限;Python 自动保留原样 |
| 浮点数转字符串 | to_string(double) | str(float) | 需要控制格式时用 ostringstream 或 f-string |
| 字符串转整数 | stoi(str) | int(str.strip()) | Python 要手动去空格;C++ 自动忽略前导空格 |
| 字符串转浮点 | stod(str) | float(str.strip()) | 同上 |
| 带进制转换 | stoi(str, nullptr, base) | int(str, base) | base 范围 2~36 |
| 非法输入处理 | try-catch (invalid_argument, out_of_range) | try-except ValueError | 必须捕获异常,程序才能继续运行 |
深入学习的指引
-
字符串流(ostringstream / istringstream)
比to_string更强大,能控制对齐、填充、精度、进制等。适合需要格式化输出或从复杂字符串中提取数字的场景。 -
C++17 的
std::from_chars
不抛异常、速度极快,适合大量数据转换。但它只解析 C 风格的数字格式(不支持 "0x" 开头十六进制等),需要自己处理错误。 -
Python 的
str.format()和 f-string
除了控制小数位,还能设置总宽度、左对齐右对齐、千位分隔符等,是格式化输出的利器。 -
正则表达式
如果字符串格式很乱(比如 "价格:19.95元"),可以先通过正则表达式提取数字部分,再转换。 -
进制转换扩展
除了 2、8、10、16 进制,C++ 和 Python 都支持 3~36 进制。你可以写一个进制转换器,比如把十进制数转换成任意进制字符串(自己实现辗转相除法)。
掌握了这些,你就能在数字和文字之间自由切换,无论是写记账程序、成绩计算器还是猜数字游戏,都不在话下。快去试试吧!
例题精讲
在C++中,将字符串"123"转换为整数,应使用哪个标准库函数?
执行std::string s = std::to_string(3.14159);后,s的值最可能是什么?
使用std::stoi("10abc")会抛出std::invalid_argument异常。
使用std::stringstream对象可以实现数值到字符串的转换。
补全以下代码,将整数x=2024转换为字符串并赋值给str:
int x = 2024;
std::string str = ___ ;