atoi,itoa,to_string,sprintf,const char* str

在 C++ 中,atoi 的具体实现逻辑可以使用基本的字符串解析方法来完成。下面我们手写一个 atoi 实现,尽量接近标准库的行为。


1. atoi 的实现逻辑

  1. 跳过前导空格
  2. 处理正负号
  3. 转换数字
  4. 处理溢出(INT_MAX 和 INT_MIN)
  5. 遇到非数字字符停止解析

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 = 2147483647
  • INT_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;

这样写,代码更现代、更可读,并且不会导致缓冲区溢出!🚀

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值