在 C++ 中,atoi 的具体实现逻辑可以使用基本的字符串解析方法来完成。下面我们手写一个 atoi 实现,尽量接近标准库的行为。
1. atoi 的实现逻辑
- 跳过前导空格
- 处理正负号
- 转换数字
- 处理溢出(INT_MAX 和 INT_MIN)
- 遇到非数字字符停止解析
2. atoi 的 C++ 实现
#include <iostream>
#include <climits> // 包含 INT_MAX 和 INT_MIN
int myAtoi(const char* str) {
if (!str) return 0; // 处理空指针
int result = 0;
int sign = 1;
const char* p = str;
// 1. 跳过前导空格
while (*p == ' ') {
p++;
}
// 2. 处理正负号
if (*p == '-') {
sign = -1;
p++;
} else if (*p == '+') {
p++;
}
// 3. 解析数字
while (*p >= '0' && *p <= '9') {
int digit = *p - '0';
// 4. 处理溢出
if (result > (INT_MAX - digit) / 10) {
return (sign == 1) ? INT_MAX : INT_MIN;
}
result = result * 10 + digit;
p++;
}
return result * sign;
}
int main() {
const char* str1 = "42";
const char* str2 = " -42";
const char* str3 = "4193 with words";
const char* str4 = "words and 987";
const char* str5 = "-91283472332"; // 超出 int 范围
const char* str6 = "2147483648"; // INT_MAX + 1
std::cout << "myAtoi(\"42\") = " << myAtoi(str1) << std::endl;
std::cout << "myAtoi(\" -42\") = " << myAtoi(str2) << std::endl;
std::cout << "myAtoi(\"4193 with words\") = " << myAtoi(str3) << std::endl;
std::cout << "myAtoi(\"words and 987\") = " << myAtoi(str4) << std::endl;
std::cout << "myAtoi(\"-91283472332\") = " << myAtoi(str5) << std::endl;
std::cout << "myAtoi(\"2147483648\") = " << myAtoi(str6) << std::endl;
return 0;
}
3. 关键点解析
(1) 跳过空格
while (*p == ' ') {
p++;
}
如果字符串有前导空格(如 " 42"),先跳过空格。
(2) 处理正负号
if (*p == '-') {
sign = -1;
p++;
} else if (*p == '+') {
p++;
}
如果遇到 '-',标记 sign = -1,如果是 '+',保持 sign = 1。
(3) 解析数字
while (*p >= '0' && *p <= '9') {
int digit = *p - '0';
result = result * 10 + digit;
p++;
}
- 遍历字符串,把连续的数字转换成整数。
digit = *p - '0',将字符转换为整数。
(4) 处理整数溢出
在 result = result * 10 + digit; 之前,需要确保不会溢出:
if (result > (INT_MAX - digit) / 10) {
return (sign == 1) ? INT_MAX : INT_MIN;
}
INT_MAX = 2147483647INT_MIN = -2147483648- 若
result > (INT_MAX - digit) / 10,说明再加上digit就会溢出。
4. 示例结果
myAtoi("42") = 42
myAtoi(" -42") = -42
myAtoi("4193 with words") = 4193
myAtoi("words and 987") = 0
myAtoi("-91283472332") = -2147483648
myAtoi("2147483648") = 2147483647
✅ "4193 with words" 解析出 4193,但遇到非数字字符时停止。
✅ "words and 987" 解析失败,返回 0。
✅ "-91283472332" 发生溢出,返回 INT_MIN = -2147483648。
✅ "2147483648" 发生溢出,返回 INT_MAX = 2147483647。
5. 总结
- 与
atoi()的行为一致,支持空格、正负号、溢出检查。 - 更安全,防止
int溢出,避免未定义行为(UB)。 - 改进点:
- 如果希望支持
long long,可以使用long long result代替int result。 - 若需要错误检测,建议使用
strtol()。
- 如果希望支持
6. std::stoi() 现代 C++ 替代
C++11 引入了 std::stoi(),它是 atoi() 的更现代化版本:
#include <iostream>
#include <string>
int main() {
std::string str = "123";
int num = std::stoi(str);
std::cout << "stoi(\"123\") = " << num << std::endl;
return 0;
}
相比 atoi(),stoi() 支持异常处理,更安全。
7. 结论
- ✅
atoi()简单,但无法处理错误,可能溢出。 - ✅
myAtoi()模拟atoi()行为,防止溢出。 - ✅
std::stoi()是 C++11 以后推荐的做法。
如果是现代 C++,建议使用 std::stoi()!🚀
itoa(Integer to ASCII)
itoa 是 C/C++ 中的一个非标准函数,用于将整数转换为字符串。虽然 itoa 在某些编译器(如 MSVC)中可用,但它不是标准 C++ 或 C 标准库的一部分,不同的实现可能有所不同。因此,在可移植代码中建议使用 sprintf() 或 std::to_string() 作为替代方案。
1. itoa 的函数原型
在 MSVC(Visual Studio)中:
#include <cstdlib>
char* itoa(int value, char* str, int base);
- 参数:
value:要转换的整数。str:存储转换结果的字符数组(用户必须确保足够大)。base:进制(如 10 进制、16 进制等)。
- 返回值:
- 指向
str的指针。
- 指向
2. itoa 的使用示例
#include <iostream>
#include <cstdlib> // MSVC 支持 itoa
int main() {
char buffer[20]; // 存储转换后的字符串
itoa(1234, buffer, 10); // 10 进制转换
std::cout << "itoa(1234, 10) = " << buffer << std::endl;
itoa(-5678, buffer, 10); // 负数转换
std::cout << "itoa(-5678, 10) = " << buffer << std::endl;
itoa(255, buffer, 16); // 16 进制转换
std::cout << "itoa(255, 16) = " << buffer << std::endl;
return 0;
}
输出
itoa(1234, 10) = 1234
itoa(-5678, 10) = -5678
itoa(255, 16) = ff
⚠️ 注意:
itoa不是 C/C++ 标准库的一部分,某些编译器(如 GCC)不支持。- 可移植代码建议使用
sprintf()或std::to_string()。
3. itoa 的 C++ 实现
如果你的编译器不支持 itoa,你可以自己实现一个:
#include <iostream>
#include <cstring>
void myItoa(int value, char* str, int base) {
if (base < 2 || base > 36) { // 基数范围 [2, 36]
*str = '\0';
return;
}
char* ptr = str;
char* start = str;
bool isNegative = false;
if (value < 0 && base == 10) { // 处理负数(仅限10进制)
isNegative = true;
value = -value;
}
// 逐位转换
do {
int digit = value % base;
*ptr++ = (digit < 10) ? ('0' + digit) : ('a' + digit - 10);
value /= base;
} while (value > 0);
if (isNegative) {
*ptr++ = '-';
}
*ptr = '\0'; // 添加字符串终止符
std::reverse(start, ptr); // 反转字符串
}
int main() {
char buffer[20];
myItoa(1234, buffer, 10);
std::cout << "myItoa(1234, 10) = " << buffer << std::endl;
myItoa(-5678, buffer, 10);
std::cout << "myItoa(-5678, 10) = " << buffer << std::endl;
myItoa(255, buffer, 16);
std::cout << "myItoa(255, 16) = " << buffer << std::endl;
return 0;
}
实现要点
- 支持 2~36 进制转换(如
2表示二进制,16表示十六进制)。 - 负数支持(仅限 10 进制)。
- 手动反转字符串(因为我们是从低位往高位存储字符)。
- 无动态内存分配(用户需提供足够大的
char数组)。
4. 更现代的替代方案
(1) std::to_string()
C++11 提供了更方便的 std::to_string(),它是标准库推荐的方式:
#include <iostream>
#include <string>
int main() {
int num = 1234;
std::string str = std::to_string(num);
std::cout << "std::to_string(1234) = " << str << std::endl;
return 0;
}
✅ 优点:
- 标准化(适用于所有 C++ 编译器)。
- 自动分配内存(返回
std::string)。 - 简单易用。
(2) sprintf()
在 C 语言中,sprintf() 也是一个常见的替代方案:
#include <iostream>
#include <cstdio>
int main() {
char buffer[20];
sprintf(buffer, "%d", 1234);
std::cout << "sprintf(1234) = " << buffer << std::endl;
return 0;
}
✅ 优点:
- 支持格式化输出(
%d、%x等)。 - 比
itoa更通用,且 C 标准支持。
❌ 缺点:
- 容易导致缓冲区溢出(如果
buffer太小)。 - 不如
std::to_string()直观。
5. 总结
| 方法 | 是否标准 | 支持负数 | 支持多进制 | 适用场景 |
|---|---|---|---|---|
itoa() | ❌(非标准) | ✅(仅十进制) | ✅ | MSVC(Windows),但不推荐 |
myItoa() | ✅(自定义实现) | ✅ | ✅ | 适用于移植性代码 |
std::to_string() | ✅(C++11) | ✅ | ❌(仅10进制) | C++ 最推荐的方式 |
sprintf() | ✅(C 标准库) | ✅ | ✅ | C 语言风格,但要注意缓冲区 |
6. 结论
- C++11 及以上 推荐使用
std::to_string(),它标准、安全、简洁。 - C 语言 可使用
sprintf(),但要小心缓冲区溢出。 itoa()不是标准函数,某些编译器(如 GCC)不支持,因此不建议使用。- 如果需要手写
itoa,可以参考myItoa()实现。
💡 最佳实践(C++ 代码):
std::string str = std::to_string(1234);
std::cout << str << std::endl;
这样写,代码更现代、更可读,并且不会导致缓冲区溢出!🚀
353

被折叠的 条评论
为什么被折叠?



