如何判断 c 函数 atoi 是不是失败或是不是是一串零?
Posted
技术标签:
【中文标题】如何判断 c 函数 atoi 是不是失败或是不是是一串零?【英文标题】:How do I tell if the c function atoi failed or if it was a string of zeros?如何判断 c 函数 atoi 是否失败或是否是一串零? 【发布时间】:2009-10-28 23:10:45 【问题描述】:当使用函数atoi
(或strtol
或类似的函数)时,如何判断整数转换是否失败,或者被转换的C字符串是否为0
?
对于我正在做的事情,0
是一个可接受的值,并且正在转换的 C 字符串可能包含任意数量的 0
s。它也可能有前导空格。
【问题讨论】:
为什么你认为 strtol() 已被弃用?这是 C 标准中一个非常好的、健全的功能。如果您关心成功/失败,那么您显然不应该使用 atoi();它无法告诉你它是成功返回 0 还是失败返回 0。 atoi 没有被弃用,它从一开始就没有出现在标准中。这是一个来自 K&R 的示例,被视为有用的扩展。 很好。我不知道 atoi 的历史或详细信息,并删除了任何对弃用的引用。 @stonemetal:不正确。atoi
和整个ato...
公司都是标准功能。它们也出现在 C99 中。
接受的答案已过时;请参阅emlai's answer。
【参考方案1】:
正确的函数(只要你坚持使用C风格的函数)是strtol
,转换代码可能如下所示
const char *number = "10"; /* for example */
char *end;
long value = strtol(number, &end, 10);
if (end == number || *end != '\0' || errno == ERANGE)
/* ERROR, abort */;
/* Success */
/* Add whatever range checks you want to have on the value of `value` */
一些备注:
strtol
允许(意思是:悄悄地跳过)实际数字前面的空格。如果您将此类前导空格视为错误,则必须自己检查。
检查*end != '\0'
确保数字后面没有任何内容。如果您想在实际数字(空格?)之后允许其他字符,则必须相应地修改此检查。
附:我稍后添加了end == number
检查以捕获空输入序列。 *end != '\0'
单独检查会捕获“所有空格”和“根本没有数字”输入。不过,提前捕获空输入可能是有意义的。在这种情况下,end == number
检查将/可能变得不必要。
【讨论】:
应该是end == number
(没有取消引用)。
糟糕...对不起。固定的。谢谢。
如果仅限于使用 C 而不是 C++,这是一个很好的解决方案。我只接触过atoi
,所以我不知道有哪些选择。您对strol
的使用显然是一个更好的C 解决方案,但我能够使用C++(尽管只有std 库),所以模拟Boost 库中的lexical_cast
的模板转换函数最适合我的使用。不过谢谢!我相信这在某个时候会派上用场! :)
(end == number)
检查不够吗? C99 标准规定(TR1,2 版本标准为 7.20.1.4-7)“如果主题序列为空或不具有预期形式,则不进行转换;nptr 的值存储在指向的对象中到 endptr,前提是 endptr 不是空指针。”。
@XAleXOwnZX:你所说的在形式上是正确的。但我反对在纯粹的风格原则上仅使用*end
。在我的书中,只有具有显式布尔语义的值才允许在没有显式比较运算符的逻辑表达式中使用。所有其他值都应与显式比较运算符一起使用,无论它是否“冗余”。在这种特殊情况下,我认为在逻辑表达式中使用*end
是一种糟糕的编码风格和一种糟糕的编程习惯。我个人坚持使用*end != '\0'
。【参考方案2】:
由于这是标记c++:
template< typename T >
inline T convert(const std::string& str)
std::istringstream iss(str);
T obj;
iss >> std::ws >> obj >> std::ws;
if(!iss.eof())
throw "dammit!";
return obj;
【讨论】:
我可以使用 C++,所以也许这比使用 strtol 更好,但我不明白这段代码。 @Jared:如果您删除template< typename T>
并将所有 T
替换为 int
,是否更容易理解?该函数使用要读取的字符串初始化输入流,创建一个对象,并尝试从流中读取到对象中。如果读取失败或除空格之外的任何内容在要读取的内容之前/之后,则该函数应发出错误(我已通过抛出异常来表示)。如果一切顺利,则返回对象。如果您对不清楚的地方更具体一点,我可以对此进行扩展。
现在我已经花了一些时间来理解模板,这很有意义并且是一个完美的解决方案!谢谢!我发现了一个更详细的帖子,其中也有几个不同的选项:***.com/questions/1243428/…
是的,GMan 的版本更复杂一点。 :)
这个答案已经过时了;请参阅emlai's answer。【参考方案3】:
对于 C++11 及更高版本:
字符串到整数转换的首选函数现在是 stoi
,它接受 string
并返回 int
,或者在出错时引发异常。
不再需要接受答案中提到的冗长的istringstream
hack。
(还有stol
/stoll
/stof
/stod
/stold
分别为long
/long long
/float
/double
/@987654335转换。)
【讨论】:
这确实应该是现在公认的答案。另外,请注意std::stoi
引发的异常是std::invalid_argument
。
@ray 也可能抛出std::out_of_range
.【参考方案4】:
来自 strtol() 的手册页:
如果endptr不为NULL,strtol()存储第一个无效的地址 *endptr 中的字符。但是,如果根本没有数字,则 strtol() 将 nptr 的原始值存储在 *endptr 中。 (因此,如果 *nptr 不是
'\0'
但 **endptr 返回时为'\0'
,整个字符串都是有效的。)
【讨论】:
【参考方案5】:自从我完成 C/C++ 以来已经有一段时间了,但在我看来,(过于)简单的解决方案是只检查字符串中的“0”。
int value = atoi(string_number.c_str());
if ( !value && string_number != "0" )
// error
else
// great success!
【讨论】:
00
、+0
、-0
、<whitespace>0
怎么样。这些错误也是?我知道他们可能是从用户的角度来看的。但请记住,从传统标准库的角度来看,这些不是错误。例如,atoi
、strtol
、scanf
...
string_number 可能包含任意数量的零,所以这不是一个理想的解决方案,尽管我考虑过。还是谢谢。
一年后投反对票?我想知道为什么。希望有建设性的东西。【参考方案6】:
strtol
的替代品是sscanf
,虽然它有点重:
const char *numStr = "12345"; // input string
int value;
if(sscanf(numStr, "%d", &value) == 1)
; // parsing succeeded, use value
else
; // error
但是,这允许在您的字符串中使用前导空格(这可能是可取的,也可能不是可取的),并且它允许任何东西尾随数字,因此“123abc”将被接受并返回 123。如果您想要更严格的控制,使用strtol()
,作为AndreyT demonstrates。
【讨论】:
sscanf
比atoi
更好,因为它至少提供了一些反馈。但是,它仍然是有限的。 sscanf
,不幸的是,无法在溢出中幸存下来。在溢出的情况下,sscanf
会产生未定义的行为。这就是为什么strto...
family 基本上是在 C 标准库中执行转换的唯一可靠方法。以上是关于如何判断 c 函数 atoi 是不是失败或是不是是一串零?的主要内容,如果未能解决你的问题,请参考以下文章