【C|C++】字符串转整数

库函数 atoi 与 stoi

atoi (ASCII to Integer) 是一个常见的 C 语言库函数,用于将字符串转换为整数。stoi 是 C++标准库中的一个函数,也用于将字符串转换为整数类型。它们的函数原型如下:

1
2
3
4
5
6
7
int atoi(const char* str);
// str: 以 null 结尾的 C 风格字符串(字符数组)

int stoi(const string& str, size_t* pos = nullptr, int base = 10);
// str: 要转换的字符串
// pos(可选): 指向 size_t 类型的指针,用于存储转换后整数的位置
// base(可选): 整数,指定要使用的进制,默认是10进制。可以设置为2到36之间的值

使用案例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <iostream>
#include <iomanip> // 包含 setw
using namespace std;

vector<string> test_case = {"123", "-123", "-0", "0",
                            "-00123", "00123",
                            "1111111111111", "-1111111111111",
                            "  -10", "  10", " ", "",
                            "abc", "abc-1", "  -100abc-1", "100 100",
                            };

int main() {
    for (string s: test_case) {
        cout << "atoi(\"" + s + "\"): " << std::setw(30) << std::left << atoi(s.c_str()) << '\t';
        cout << "stoi(\"" + s + "\"): " ;
        try {
            cout << stoi(s);
        } catch (const std::invalid_argument& e) {
            cout << "[Invalid argument exception]: " << e.what();
        } catch (const std::out_of_range& e) {
            cout << "[Out of range exception]: " << e.what();
        }
        cout << endl;
    }
    return 0;
}

输出结果如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
atoi("123"): 123                                stoi("123"): 123
atoi("-123"): -123                              stoi("-123"): -123
atoi("-0"): 0                                   stoi("-0"): 0
atoi("0"): 0                                    stoi("0"): 0
atoi("-00123"): -123                            stoi("-00123"): -123
atoi("00123"): 123                              stoi("00123"): 123
atoi("1111111111111"): -1285418553              stoi("1111111111111"): [Out of range exception]: stoi: out of range
atoi("-1111111111111"): 1285418553              stoi("-1111111111111"): [Out of range exception]: stoi: out of range
atoi("  -10"): -10                              stoi("  -10"): -10
atoi("  10"): 10                                stoi("  10"): 10
atoi(" "): 0                                    stoi(" "): [Invalid argument exception]: stoi: no conversion
atoi(""): 0                                     stoi(""): [Invalid argument exception]: stoi: no conversion
atoi("abc"): 0                                  stoi("abc"): [Invalid argument exception]: stoi: no conversion
atoi("abc-1"): 0                                stoi("abc-1"): [Invalid argument exception]: stoi: no conversion
atoi("  -100abc-1"): -100                       stoi("  -100abc-1"): -100
atoi("100 100"): 100                            stoi("100 100"): 100

两者差异

atoi stoi
C++标准 C 标准库函数 C++标准库函数
参数 const char* str:C 风格字符数组指针 const string& str:字符串
size_t* pos = nullptr:转换后结果的存储位置
int base = 10:整数的进制,默认 10 进制
错误处理 没有提供错误处理机制:
- 字符串无法转换为整数,返回 0
- 转换后的值超出目标类型的范围,返回溢出值
提供错误处理机制:
- 字符串无法转换为整数,抛出 invalid_argument 异常
- 转换后的值超出目标类型的范围,抛出 out_of_range 异常

atoistoi 对空格和非数字字符的处理类似:

  • 忽略字符串开头的空格字符,遇到中间的空格或非数字字符会停止转换
  • 当前的转换值非空则返回,若没有转换值 atoi 返回 0,stoi 抛出 invalid_argument 异常

建议使用 stoi 函数,因为它提供了更好的错误处理和更严格的转换规则,也包含更多功能。如果使用 C 语言,或者仅考虑简单的转换,atoi 函数也可以满足需求。

实现自己的 atoi

需要考虑各种边界条件,面对溢出和非法字符返回 0 或抛出异常

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include <iostream>
using namespace std;

vector<string> test_case = {"123", "-123", "-0", "0",
                            "-00123", "00123",
                            "1111111111111", "-1111111111111",
                            "  -10", "  10", " ", "",
                            "abc", "abc-1", "  -100abc-1", "100 100",
                            };

// string 2 int [-2^31, 2^31-1] [-2147483648, 2147483647]
int myAtoi(const char* str) {
    if (str == NULL) return 0;

    int res = 0, sign = 1, i = 0;

    // 忽略字符串开头空格
    while (str[i] == ' ') i++;

    // 整数符号判断
    if (str[i] == '-' || str[i] == '+') {
        sign = str[i++] == '-' ? -1 : 1;
    }

    // 没有有效转化数字
    if (!(str[i] >= '0' && str[i] <= '9')) {
        throw std::invalid_argument("no conversion");
        // return 0;
    }

    // 计算数字
    for (; str[i]; i++) {
        // 非数字字符直接终止
        if (!(str[i] >= '0' && str[i] <= '9')) {
            return res * sign;
        }
        // 处理溢出
        if (res > INT_MAX / 10 || (res == INT_MAX/10 && str[i] > '7')) {
            throw std::out_of_range("out of range");
            // return sign == 1 ? INT_MAX : INT_MIN;
        }
        res = res * 10 + str[i] - '0';
    }
    return res * sign;
}

int main() {
    for (string s: test_case) {
        cout << "string2int(\"" + s + "\"): ";
        try {
            cout << myAtoi(s.c_str());
        } catch (const std::invalid_argument& e) {
            cout << "[Invalid argument exception]: " << e.what();
        } catch (const std::out_of_range& e) {
            cout << "[Out of range exception]: " << e.what();
        }
        cout << endl;
    }
    return 0;
}

Reference

0%