使用标准库函数 atoi (最简单但不安全)
atoi (ASCII to Integer) 是 C 标准库 <stdlib.h> 中提供的函数,专门用于将字符串转换为 int 类型。

(图片来源网络,侵删)
函数原型
int atoi(const char *str);
功能
它会跳过字符串开头的空白字符(空格、制表符、换行符等),然后读取一个可选的正号 或负号 ,接着读取数字字符,直到遇到第一个非数字字符为止,最后将读取到的数字转换为整数并返回。
示例代码
#include <stdio.h>
#include <stdlib.h> // 必须包含此头文件
#include <string.h> // 用于 strlen 示例
int main() {
const char *str1 = "12345";
const char *str2 = "-678";
const char *str3 = " 42 with text"; // 会忽略开头的空格,并停在 'w'
const char *str4 = "abc123"; // 无法转换,返回 0
const char *str5 = "99999999999999999999"; // 超出 int 范围,行为未定义
int num1 = atoi(str1);
int num2 = atoi(str2);
int num3 = atoi(str3);
int num4 = atoi(str4);
int num5 = atoi(str5); // 危险!结果不可预测
printf("'%s' -> %d\n", str1, num1);
printf("'%s' -> %d\n", str2, num2);
printf("'%s' -> %d\n", str3, num3);
printf("'%s' -> %d\n", str4, num4);
printf("'%s' -> %d (结果可能错误)\n", str5, num5);
return 0;
}
优点
- 简单易用:调用非常直接,一行代码就能完成转换。
缺点
- 不安全:这是
atoi最大的问题。- 错误检测缺失:如果字符串不是以数字开头(如
str4),atoi会返回0,但你无法区分“转换成功,结果是 0”和“转换失败,返回默认值 0”这两种情况。 - 溢出处理缺失:如果转换后的数字超出了
int类型的表示范围(如str5),atoi的行为是未定义(Undefined Behavior),这意味着它可能会返回一个错误的值、崩溃,或者产生任何意想不到的后果,这是非常危险的。
- 错误检测缺失:如果字符串不是以数字开头(如
使用更安全的 strtol (推荐)
strtol (String to Long) 是 C 标准库 <stdlib.h> 中提供的另一个函数,功能更强大,也更安全,它可以将字符串转换为 long 类型,并且提供了完善的错误检测和溢出处理机制。
函数原型
long strtol(const char *restrict str, char **restrict endptr, int base);
参数详解
str:要转换的字符串。endptr:这是一个指向char*指针的指针,函数执行后,*endptr会指向转换停止时的字符位置,如果整个字符串都被成功转换,*endptr将指向字符串的结尾\0,这个参数是判断转换是否完全成功的关键。base:转换的基数(进制)。base为 0,函数会自动识别字符串的进制:- 以
0x或0X开头 -> 十六进制 - 以
0开头 -> 八进制 - 其他 -> 十进制
- 以
base为 2 到 36 之间的值,则按该进制转换。base为 1 或大于 36,则行为未定义。
返回值
- 成功时,返回转换后的
long整数值。 - 如果转换的值超出了
long类型的范围,函数会返回LONG_MAX或LONG_MIN(定义在<limits.h>中),并设置全局变量errno为ERANGE。
示例代码
#include <stdio.h>
#include <stdlib.h> // for strtol, errno, LONG_MAX, LONG_MIN
#include <limits.h> // for LONG_MAX, LONG_MIN
#include <errno.h> // for errno
int main() {
const char *str1 = "12345";
const char *str2 = "-678";
const char *str3 = " 42 with text";
const char *str4 = "abc123";
const char *str5 = "99999999999999999999"; // 超出 long 范围
char *endptr; // 用于接收转换停止的位置
long num;
// 转换 str1
errno = 0; // 每次调用前重置 errno
num = strtol(str1, &endptr, 10);
if (errno == ERANGE) {
printf("错误:数值超出 long 范围!\n");
} else if (endptr == str1) {
printf("错误:无法转换 '%s',没有数字字符\n", str1);
} else {
printf("'%s' -> %ld\n", str1, num);
}
// 转换 str2
errno = 0;
num = strtol(str2, &endptr, 10);
if (errno == ERANGE) {
printf("错误:数值超出 long 范围!\n");
} else if (endptr == str2) {
printf("错误:无法转换 '%s',没有数字字符\n", str2);
} else {
printf("'%s' -> %ld\n", str2, num);
}
// 转换 str3
errno = 0;
num = strtol(str3, &endptr, 10);
if (errno == ERANGE) {
printf("错误:数值超出 long 范围!\n");
} else if (endptr == str3) {
printf("错误:无法转换 '%s',没有数字字符\n", str3);
} else {
printf("'%s' -> %ld (剩余部分: '%s')\n", str3, num, endptr);
}
// 转换 str4
errno = 0;
num = strtol(str4, &endptr, 10);
if (errno == ERANGE) {
printf("错误:数值超出 long 范围!\n");
} else if (endptr == str4) {
printf("错误:无法转换 '%s',没有数字字符\n", str4);
} else {
printf("'%s' -> %ld\n", str4, num);
}
// 转换 str5
errno = 0;
num = strtol(str5, &endptr, 10);
if (errno == ERANGE) {
printf("错误:'%s' 数值超出 long 范围!\n", str5);
} else if (endptr == str5) {
printf("错误:无法转换 '%s',没有数字字符\n", str5);
} else {
printf("'%s' -> %ld\n", str5, num);
}
return 0;
}
优点
- 安全可靠:通过
endptr和errno可以精确地判断转换是否成功、是否溢出。 - 功能强大:可以处理各种进制,并且能告诉你转换到哪里停止了。
缺点
- 比
atoi稍微复杂一些,需要理解endptr和errno的用法。
手动实现 (最灵活,但需要自己处理所有细节)
如果你不想依赖标准库,或者需要实现一些特殊的转换逻辑(比如只允许特定的数字格式),可以自己编写转换函数。
基本思路
- 跳过前导空格。
- 处理可选的正负号。
- 遍历后续的数字字符,将它们拼凑成数值。
- 检查是否溢出。
- 遇到非数字字符时停止。
示例代码
#include <stdio.h>
#include <ctype.h> // for isdigit
#include <limits.h> // for INT_MAX, INT_MIN
int my_str_to_int(const char *str) {
int sign = 1; // 默认为正数
int result = 0;
int i = 0;
// 1. 跳过前导空格
while (isspace(str[i])) {
i++;
}
// 2. 处理正负号
if (str[i] == '-') {
sign = -1;
i++;
} else if (str[i] == '+') {
i++;
}
// 3. 遍历数字字符
while (isdigit(str[i])) {
int digit = str[i] - '0'; // 将字符 '0'-'9' 转换为 0-9
// 4. 检查正数溢出
if (sign == 1 && result > (INT_MAX - digit) / 10) {
// result * 10 + digit 会大于 INT_MAX
return INT_MAX; // 返回 int 的最大值
}
// 5. 检查负数溢出
if (sign == -1 && result > (INT_MAX - digit) / 10) {
// 这里需要特殊处理,因为 INT_MIN 的绝对值比 INT_MAX 大 1
// result * 10 + digit >= -(INT_MIN),则溢出
// 简化为:result > (INT_MAX - digit) / 10
return INT_MIN; // 返回 int 的最小值
}
result = result * 10 + digit;
i++;
}
return sign * result;
}
int main() {
const char *str1 = "12345";
const char *str2 = "-678";
const char *str3 = " 42";
const char *str4 = "abc123";
const char *str5 = "2147483647"; // INT_MAX
const char *str6 = "2147483648"; // 比 INT_MAX 大 1
printf("'%s' -> %d\n", str1, my_str_to_int(str1));
printf("'%s' -> %d\n", str2, my_str_to_int(str2));
printf("'%s' -> %d\n", str3, my_str_to_int(str3));
printf("'%s' -> %d\n", str4, my_str_to_int(str4));
printf("'%s' -> %d\n", str5, my_str_to_int(str5));
printf("'%s' -> %d (溢出,返回 INT_MIN)\n", str6, my_str_to_int(str6));
return 0;
}
优点
- 完全控制:你可以自定义转换逻辑,例如不允许前导空格,或者自定义错误处理方式。
- 不依赖库函数:在某些嵌入式或特殊环境下可能有用。
缺点
- 复杂且容易出错:你需要自己处理所有边界情况,包括前导空格、正负号、各种进制的可能性以及最重要的溢出检测,手动实现一个健壮的转换函数非常困难。
总结与建议
| 方法 | 优点 | 缺点 | 推荐场景 |
|---|---|---|---|
atoi |
极其简单 | 不安全,无法检测错误和溢出 | 强烈不推荐用于任何生产代码,仅用于非常简单的、确定输入绝对可靠的脚本或一次性程序。 |
strtol |
安全可靠,功能强大,可检测错误和溢出 | 比 atoi 稍复杂 |
强烈推荐,这是 C 语言中将字符串转换为整数的标准、安全、正确的方式。 |
| 手动实现 | 完全控制,灵活 | 复杂,极易出错,需要自己处理所有细节 | 当有特殊需求(如自定义格式)或在不允许使用标准库的极端环境下。 |
最终建议:

(图片来源网络,侵删)
在 C 语言开发中,请始终优先使用 strtol 函数,它虽然比 atoi 多两个参数,但带来的安全性和可靠性是完全值得的,它能帮助你写出更健壮、更不容易出错的代码,只有在 strtol 无法满足你的特殊需求时,才考虑自己动手实现。

(图片来源网络,侵删)
