字符串中的非整数数字及如何使用atoi函数

6
如果一个字符串中有非数字字符,并且您调用atoi [我假设wtoi也会这样做],那么atoi会如何处理该字符串?
例如,假设我有以下字符串:
1. "20234543" 2. "232B" 3. "B"
我相信1将返回整数20234543。我想知道的是2是否会返回"232." [这就是我需要解决的问题]。另外,3不应返回值。这些看法是否错误?此外...如果2确实像我所认为的那样,它如何处理字符串末尾的e字符?[通常用于指数表示法]

11
为什么不试一下看呢? - Michael
2
我想社区会比建立一个支持Unicode的新项目更快。 - monksy
6
“试验并观察”是可行的,但这只能展示代码在你的系统上的行为。如果想确保代码的可移植性,最好的方法是阅读标准规范。下面大部分答案都属于“试验并观察”,因此只描述了atoi在某些系统上的工作原理。 - Alok Singhal
1
“3不应该返回一个值” - 对于非void返回类型,这怎么可能呢? - Georg Fritzsche
2
有人给这个问题点了踩?有点儿傻。 - monksy
显示剩余2条评论
7个回答

10

根据标准,“函数atofatoiatolatoll在出错时不需要影响整数表达式errno的值。如果结果的值无法表示,则行为未定义。”(C99中的7.20.1,“数字转换函数”)。

因此,从技术上讲,任何事情都可能发生。即使是第一个 case,由于保证INT_MAX至少为32767,并且20234543大于该值,也可能失败。

为了更好的错误检测,请使用strtol

const char *s = "232B";
char *eptr;
long value = strtol(s, &eptr, 10); /* 10 is the base */
/* now, value is 232, eptr points to "B" */

s = "20234543";
value = strtol(s, &eptr, 10);

s = "123456789012345";
value = strtol(s, &eptr, 10);
/* If there was no overflow, value will contain 123456789012345,
   otherwise, value will contain LONG_MAX and errno will be ERANGE */

如果你需要解析具有“e”(指数符号)的数字,那么应该使用strtod函数。当然,这种数字是浮点数,strtod函数返回double类型。如果您想将其转换为整数,则可以在检查正确范围后进行转换。


失败了,但根据MSDN整数是32位的。http://msdn.microsoft.com/zh-cn/library/296az74e.aspx - monksy
@steven:它还在顶部标注了“Microsoft Specific”。因此,如果您只关心Microsoft特定的代码,那么您不需要担心第一种情况中的溢出。但是,如果您想要可移植性,那么您就需要考虑这个问题。您的问题没有标记任何特定于平台的标签,因此我假设您想要可移植性 :-)。 - Alok Singhal
好的。我写过的大多数系统都是32位的,所以我习惯于看到这样的系统。【16位的系统早已过去了】。 - monksy
1
POSIX也要求sizeof(int)>=4 - R.. GitHub STOP HELPING ICE
只是为了补充一下关于strtol的内容,我发现基数参数0是最方便的。这会自动将数字转换为常见的进制,特别是对于正常的十进制数,以及如果数字以0x开头,则会从十六进制转换。 - Jens Gustedt

10
您可以自行测试此类内容。我从Cplusplus参考网站复制了代码。你对前两个示例的直觉是正确的,但第三个示例返回'0'。 'E'和'e'与第二个示例中的'B'一样处理。

因此,规则如下:

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


6
atoi函数在输入无法表示为整数时的行为是未定义的,因此您不能自行测试;任何调用未定义行为的测试都是无效的。cplusplus.com网站没有这样说,但cplusplus.com是一个臭名昭著的不可靠参考资料。您引用的是适用于long的规则,但已经改编成适用于int(这意味着它们实际上根本不适用于任何函数)。当您需要权威引用时,请使用标准。当您需要快速参考时,请使用cppreference.com。 - Rob Kennedy
atoi()在输入"abc123"时返回0。为什么它被视为0,但当输入"123abc"时,它显示"123"作为输出。有人能解释一下吗? - Vishnu N K
1
因为POSIX将atoi定义为具有与strtol类似的行为,它处理前导空格(如果有),然后是数字,最后是任何未识别的字符(如果有)(http://pubs.opengroup.org/onlinepubs/009695399/functions/strtol.html)。在您的第二个示例中,`strtol`遇到了无法识别的字符并放弃了。 - gladed

7

atoi函数从缓冲区读取数字,直到无法继续为止。当它遇到任何不是数字的字符时停止,除了空格(它会跳过)或在看到任何数字之前的“+”或“-”符号(它用于选择结果的适当符号)。如果它没有看到任何数字,则返回0。

因此,回答您具体的问题:1返回20234543. 2返回232. 3返回0。“e”字符既不是空格,也不是数字、“+”或“-”,因此如果遇到该字符,atoi函数将停止并返回。

另请参见这里


4
如果atoi遇到一个非数字字符,它会返回直到该字符之前所组成的数字。

0

我在一个项目中尝试使用atoi()函数,但是如果混合的字符串中有任何非数字字符并且它们出现在数字字符之前,该函数将返回零。不知道为什么,如果这些非数字字符出现在数字字符之后,该函数似乎并不介意。

下面是我编写的一个相当简单的字符串转整数转换器,它似乎没有这个问题(它不能处理负数,并且不包含任何错误处理,但在特定情况下可能会有所帮助)。希望它能有所帮助。

int stringToInt(std::string newIntString)
{
    unsigned int dataElement = 0;
    unsigned int i = 0;

    while ( i < newIntString.length())
    {
        if (newIntString[i]>=48 && newIntString[i]<=57)
        {
         dataElement += static_cast<unsigned int>(newIntString[i]-'0')*(pow(10,newIntString.length()-(i+1)));
        }
        i++;
    }
    return dataElement;
}

0

当我学习编程时,我因为atoi函数的行为而责备自己。该函数通过启动命令行参数来计算整数阶乘结果的函数。

如果值不是数字,则atoi函数返回0,而“3asdf”返回3。正如我们所知道的那样,C语言将命令行输入参数处理为char数组指针变量。

有人告诉我,在书籍《Linux Hater's Handbook》中,有一些关于计算机极客并不喜欢atoi函数的讨论,因为它是愚蠢的,原因是没有办法检查给定输入类型的有效性。

有人问我为什么不使用位于stdlib.h库中的strtol函数,并为我的阶乘计算递归方法附上了一个示例,但我不在意阶乘结果是否超出了整数主类型值范围,超出了范围(太大的基数)。这将导致我的程序产生负值。

我通过首先检查给定用户输入参数是否真正是数字值,然后计算阶乘值来解决了我的问题。

使用位于chtype.h库中的isdigit()函数如下:

int checkInput(char *str[]) {
 for (int x = 0; x < strlen(*str); ++x)
    {
        if (!isdigit(*str[x])) return 1;
    }
    return 0;
}

在另一个Linux编程论坛上,我的论坛朋友告诉我,如果我使用strtol,我可以处理超出范围的值或将有符号整数解析为无符号长类型,这意味着-0和其他负值不被接受。

重要的是,在我的代码中检查字符是否为数字值。检查这个的一种方式是当字符串中的第一个数字值出现时,函数返回失败结果进行协商(或在C中的字符数组中)。


-1
编写简单的代码并查看其运行结果是一种神奇而启迪人心的体验。
在第三点上,它不会返回“nothing”。它不能。它将返回某些东西,但那些东西对你来说没有用处。

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

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

我知道它会返回0 [或一个集合值] 或null。但我不确定。但我的问题是...它是否转换为下一个非整数值? - monksy
"next non-integer value" 是什么意思? - dash-tom-bang
你说得对它不能返回“nothing”,但这并不意味着它会返回“something”。行为未定义,所以有可能根本不会返回。 - Rob Kennedy
@RobKennedy,在哪个方面行为是未定义的?根据我刚刚粘贴的引用,它似乎完全被定义了。也就是说,如果你向函数传递垃圾值,那么你将得到垃圾返回值。 - dash-tom-bang
2
你所贴的引用来自一个臭名昭著的错误网站。请检查标准,或者查看该网站今天发布的内容。 - Rob Kennedy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接