52

http://www.cplusplus.com/reference/clibrary/cstdlib/atoi/

返回值

成功时,函数将转换后的整数作为int值返回。 如果无法执行有效转换,则返回零值。 如果正确值超出可表示值的范围,则返回 INT_MAX 或 INT_MIN。

所以我在atoi("poop")atoi("0")和之间有什么不同atoi("0000000")

是的,如果我得到 0 结果,我可以循环并检查所有零,但没有更好的方法吗?

注意:我使用 ANSI C89

4

3 回答 3

49

atoi这就是有时被认为不安全的原因之一。使用strtol/strtoul代替。如果你有它,请使用strtonum.

该功能atoi比您想象的更危险。标准POSIX

如果无法表示该值,则行为未定义。

C99 标准也这样说:

7.20.1

函数 atof、atoi、atol 和 atoll 在出现错误时不需要影响整数表达式 errno 的值。如果结果的值无法表示,则行为未定义。

于 2012-01-15T17:26:17.470 回答
20

正如@cnicutar 和@ouah 所描述的,atoi无法区分有效的0 和无效的字符串,从而使strtol系列成为更好的选择。

但是为什么?以及如何?首先要了解两者atoi并且strtol仅将字符串中的初始数字集转换为数值。任何尾随的非数字字符都将被忽略。strtol可用于检查无效字符串,因为除了数值之外,它还返回指向字符串数字部分末尾的指针。因此,如果该end指针仍然指向原始字符串的开头,则可以判断存在错误并且字符串中没有字符被转换。

如代码示例所示,还有一些其他细微之处:

long lnum;
int num;
char *end;

errno = 0;

lnum = strtol(in_str, &end, 10);        //10 specifies base-10
if (end == in_str)     //if no characters were converted these pointers are equal
    fprintf(stderr, "ERROR: can't convert string to number\n");

//If sizeof(int) == sizeof(long), we have to explicitly check for overflows
if ((lnum == LONG_MAX || lnum == LONG_MIN) && errno == ERANGE)  
    fprintf(stderr, "ERROR: number out of range for LONG\n");

//Because strtol produces a long, check for overflow
if ( (lnum > INT_MAX) || (lnum < INT_MIN) )
    fprintf(stderr, "ERROR: number out of range for INT\n");

//Finally convert the result to a plain int (if that's what you want)
num = (int) lnum;

注意:如果您确定输入字符串将在有效的 int 范围内,您可以消除lnum并直接转换 strtol 的 return:num = (int) strtolen(in_str, &end, 10);

于 2013-08-31T04:21:43.620 回答
7

你不能。

atoi无法检测错误。如果无法表示结果,则atoi调用未定义的行为。使用strtol而不是atoi.

安全 CERT 编码建议使用strtol而不是atoi,请阅读:

INT06-C。使用 strtol() 或相关函数将字符串标记转换为整数

于 2012-01-15T17:26:42.870 回答