字符串与数字转换
C 标准库提供了多种字符串与数字之间的转换函数。<stdlib.h> 中的 atoi、atol、atof 等函数简单易用但缺乏错误检测;strtol、strtod 等函数更健壮,能检测溢出和无效输入。理解这些函数的特性和限制,能帮助你安全地处理数字字符串转换。
简单转换函数
atoi:字符串转 int
#include <stdlib.h>
int n = atoi("123"); /* 123 */
int m = atoi("-456"); /* -456 */
int bad = atoi("abc"); /* 0:无法转换 */
int huge = atoi("999999999999999999999"); /* 溢出,结果未定义 */
atoi 的问题:
- 无法区分"转换失败"和"转换结果为 0"
- 不检测溢出
- 不报告错误
atol:字符串转 long
long n = atol("1234567890");
atof:字符串转 double
double d = atof("3.14159");
健壮转换函数
strtol:字符串转 long(推荐)
#include <stdlib.h>
#include <errno.h>
char *str = "12345";
char *endptr;
long value;
errno = 0; /* 清除之前的错误 */
value = strtol(str, &endptr, 10); /* 10 进制 */
if (endptr == str) {
printf("No digits found\n"); /* 转换失败 */
} else if (errno == ERANGE) {
printf("Overflow or underflow\n"); /* 超出范围 */
} else {
printf("Value: %ld\n", value); /* 12345 */
printf("Remaining: %s\n", endptr); /* 空字符串 */
}
strtol 的参数:
str:要转换的字符串endptr:指向转换停止的位置(可为 NULL)base:进制(2-36,0 表示自动检测)
strtoul:字符串转 unsigned long
unsigned long value = strtoul("0xFF", &endptr, 0); /* 自动检测进制:255 */
unsigned long value2 = strtoul("077", &endptr, 0); /* 自动检测:八进制 63 */
unsigned long value3 = strtoul("99", &endptr, 0); /* 十进制 99 */
strtod:字符串转 double
double value = strtod("3.14159e10", &endptr);
数字转字符串
sprintf / snprintf:
char buffer[100];
int n = 42;
sprintf(buffer, "%d", n); /* 不安全 */
snprintf(buffer, sizeof(buffer), "%d", n); /* 安全 */
/* 格式化选项 */
snprintf(buffer, sizeof(buffer), "%08d", n); /* "00000042" */
snprintf(buffer, sizeof(buffer), "%x", n); /* "2a" */
snprintf(buffer, sizeof(buffer), "%.2f", 3.14159); /* "3.14" */
进制转换
/* 任意进制(2-36) */
char *str = "1A3F";
long value = strtol(str, NULL, 16); /* 6719 */
char *bin = "101010";
long val2 = strtol(bin, NULL, 2); /* 42 */
/* 转回字符串 */
char buffer[100];
snprintf(buffer, sizeof(buffer), "%X", 6719); /* "1A3F" */
常见错误
不检查 atoi 错误:
int value = atoi(user_input); /* 如果输入 "abc",value = 0 */
/* 无法区分是 0 还是错误 */
/* 正确 */
char *endptr;
long value = strtol(user_input, &endptr, 10);
if (*endptr != '\0') {
printf("Invalid input\n");
}
溢出不检测:
int value = atoi("99999999999999999999"); /* 溢出,结果未定义 */
/* 正确 */
errno = 0;
long value = strtol(str, &endptr, 10);
if (errno == ERANGE) {
printf("Number too large\n");
}
sprintf 溢出:
char buffer[10];
int n = 1234567890;
sprintf(buffer, "%d", n); /* 越界!需要 10 字符 + '\0' */
/* 正确 */
snprintf(buffer, sizeof(buffer), "%d", n); /* 安全截断 */
最佳实践
- 用
strtol、strtod替代atoi、atof - 始终检查
endptr和errno - 数字转字符串用
snprintf,不用sprintf - 处理用户输入时,验证转换结果
- 注意进制前缀(
0x十六进制,0八进制) - 明确指定进制,避免意外行为