将字符串转换为整数的sscanf和atoi之间有什么区别?
通用条款4.4.4 c89 最好将字符串转换为整数值 我尝试了两种不同的方法atoi和sscanf。两种方法都能如期工作将字符串转换为整数的sscanf和atoi之间有什么区别?,c,scanf,atoi,C,Scanf,Atoi,通用条款4.4.4 c89 最好将字符串转换为整数值 我尝试了两种不同的方法atoi和sscanf。两种方法都能如期工作 char digits[3] = "34"; int device_num = 0; if(sscanf(digits, "%d", &device_num) == EOF) { fprintf(stderr, "WARNING: Incorrect value for device\n"); return FALSE; } 或者使用atoi de
char digits[3] = "34";
int device_num = 0;
if(sscanf(digits, "%d", &device_num) == EOF) {
fprintf(stderr, "WARNING: Incorrect value for device\n");
return FALSE;
}
或者使用atoi
device_num = atoi(digits);
我认为sscanf会更好,因为您可以检查错误。但是,atoi不进行任何检查。*scanf()
函数族返回转换的值的数量。因此,您应该检查以确保sscanf()
在您的案例中返回1EOF
返回“输入失败”,这意味着ssacnf()
永远不会返回EOF
对于sscanf()
,函数必须解析格式字符串,然后解码整数atoi()
没有这种开销。两者都存在值超出范围导致未定义行为的问题
您应该使用strtol()
或strtoul()
函数,它们提供了更好的错误检测和检查。它们还让您知道整个字符串是否已被使用
如果您想要一个
int
,您可以始终使用strtol()
,然后检查返回值是否介于int\u MIN
和int\u MAX
之间。如果用户输入34abc并将其传递给atoi,则返回值将为34。
如果要验证输入的值,则必须对输入的字符串反复使用isdigit您有3种选择:
atoi
int
,则行为未指定
sscanf
“%d”
将返回0。您可以使用“%d%n”
存储在另一个变量中读取的整数之后的第一个字符的索引,从而检查整个字符串是否已转换,或者之后是否有垃圾。但是,与atoi
一样,整数溢出的行为是未指定的
strtol
和系列errno
设置为0。返回值在溢出时指定,并且将设置errno
。您可以选择2到36之间的任何数字基数,或者指定0作为基数,以分别将前导0x
和0
自动解释为十六进制和八进制。要转换为的类型选择是long/long-long/intmax\t
的有符号/无符号版本
如果需要较小的类型,您可以始终将结果存储在临时long
或unsigned long
变量中,并自行检查溢出
由于这些函数采用指向指针的指针参数,因此还可以免费获得指向转换后的整数后面的第一个字符的指针,因此可以判断整个字符串是否为整数,或者在需要时解析字符串中的后续数据
就我个人而言,我推荐
strtol
系列用于大多数目的。如果你做的事情又快又脏,atoi可能会满足你的需要
顺便说一句,有时我发现我需要解析那些不应该接受前导空格、符号等的数字。在这种情况下,很容易推出自己的for循环,例如
for (x=0; (unsigned)*s-'0'<10; s++)
x=10*x+(*s-'0');
致@R。。我认为在
strtol
调用中检查errno
以检测错误是不够的
long strtol (const char *String, char **EndPointer, int Base)
您还需要检查端点是否有错误。。。皮克博伊的回答很简洁
long strtol (const char *String, char **EndPointer, int Base)
// examples
strtol(s, NULL, 10);
strtol(s, &s, 10);
如果不担心无效字符串输入或范围问题,请使用最简单的:
atoi()
否则,具有最佳错误/范围检测的方法既不是atoi()
,也不是sscanf()
。
all ready详细说明了使用atoi()
进行错误检查的不足,以及使用sscanf()
进行的一些错误检查
strtol()
是将字符串转换为int
时最严格的函数。但这只是一个开始。下面是详细的例子来说明正确的用法,以及在后面给出这个答案的原因
这类似于atoi()
,并且忽略了使用strtol()
的错误检测功能
要充分使用strtol(),需要考虑以下各种功能:
“xyz”
,或“
或”--0“
?在这些情况下,endptr
将匹配nptr
char *endptr;
int i = (int)strtol(nptr, &endptr, 10);
if (nptr == endptr) return FAIL_NO_CONVERT;
“123xyz”
可以吗
char *endptr;
int i = (int)strtol(nptr, &endptr, 10);
if (*endptr != '\0') return FAIL_EXTRA_JUNK;
长的,如“999999999999999999999999999”
int
范围,但不在long
范围内。如果int
和long
具有相同的范围,则不需要进行此测试
long L = strtol(nptr, &endptr, 10);
if (L < INT_MIN || L > INT_MAX) return FAIL_INT_OVERFLOW;
注意:前面提到的所有函数都允许前导空格,这是一个可选的前导符号字符,并且受区域设置更改的影响。更严格的转换需要额外的代码
注:非OP标题更改偏重强调。这个答案更适用于原始标题“将字符串转换为整数sscanf或atoi”作为
strtol
等的额外奖励,如果您将基数设置为0
,则会自动选择转换
char *endptr;
int i = (int)strtol(nptr, &endptr, 10);
if (*endptr != '\0') return FAIL_EXTRA_JUNK;
errno = 0;
long L = strtol(nptr, &endptr, 10);
if (errno == ERANGE) return FAIL_OVERFLOW;
long L = strtol(nptr, &endptr, 10);
if (L < INT_MIN || L > INT_MAX) return FAIL_INT_OVERFLOW;
#include <errno.h>
#include <stdlib.h>
int strtoi(const char *nptr, int *error_code) {
char *endptr;
errno = 0;
long i = strtol(nptr, &endptr, 10);
#if LONG_MIN < INT_MIN || LONG_MAX > INT_MAX
if (errno == ERANGE || i > INT_MAX || i < INT_MIN) {
errno = ERANGE;
i = i > 0 : INT_MAX : INT_MIN;
*error_code = FAIL_INT_OVERFLOW;
}
#else
if (errno == ERANGE) {
*error_code = FAIL_OVERFLOW;
}
#endif
else if (endptr == nptr) {
*error_code = FAIL_NO_CONVERT;
} else if (*endptr != '\0') {
*error_code = FAIL_EXTRA_JUNK;
} else if (errno) {
*error_code = FAIL_IMPLEMENTATION_REASON;
}
return (int) i;
}