我试图找出是否有一种在C中将字符串转换为整数的替代方法.
我经常在我的代码中模式化以下内容.
char s[] = "45";
int num = atoi(s);
Run Code Online (Sandbox Code Playgroud)
那么,有更好的方式或其他方式吗?
cni*_*tar 167
有strtol
更好的IMO.我也很喜欢strtonum
,所以如果你有它,请使用它(但记住它不便携):
long long
strtonum(const char *nptr, long long minval, long long maxval,
const char **errstr);
Run Code Online (Sandbox Code Playgroud)
您可能也感兴趣strtoumax
,strtoimax
哪些是C99中的标准功能.例如你可以说:
uintmax_t num = strtoumax(s, NULL, 10);
if (num == UINTMAX_MAX && errno == ERANGE)
/* Could not convert. */
Run Code Online (Sandbox Code Playgroud)
无论如何,远离atoi
:
呼叫atoi(str)应相当于:
Run Code Online (Sandbox Code Playgroud)(int) strtol(str, (char **)NULL, 10)
除了错误的处理可能不同.如果无法表示该值,则行为未定义.
AnT*_*AnT 24
不要使用ato...
组中的功能.这些都是破碎的,几乎没用.sscanf
虽然它也不是完美的,但使用的解决方案会更好.
要将字符串转换为整数,strto...
应使用group中的函数.在你的具体情况下,它将是strtol
功能.
Cir*_*四事件 24
基于C89 strtol
的强大解决方案
附:
atoi
家人一样)strtol
(例如没有前导空格或尾随垃圾字符)#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
typedef enum {
STR2INT_SUCCESS,
STR2INT_OVERFLOW,
STR2INT_UNDERFLOW,
STR2INT_INCONVERTIBLE
} str2int_errno;
/* Convert string s to int out.
*
* @param[out] out The converted int. Cannot be NULL.
*
* @param[in] s Input string to be converted.
*
* The format is the same as strtol,
* except that the following are inconvertible:
*
* - empty string
* - leading whitespace
* - any trailing characters that are not part of the number
*
* Cannot be NULL.
*
* @param[in] base Base to interpret string in. Same range as strtol (2 to 36).
*
* @return Indicates if the operation succeeded, or why it failed.
*/
str2int_errno str2int(int *out, char *s, int base) {
char *end;
if (s[0] == '\0' || isspace(s[0]))
return STR2INT_INCONVERTIBLE;
errno = 0;
long l = strtol(s, &end, base);
/* Both checks are needed because INT_MAX == LONG_MAX is possible. */
if (l > INT_MAX || (errno == ERANGE && l == LONG_MAX))
return STR2INT_OVERFLOW;
if (l < INT_MIN || (errno == ERANGE && l == LONG_MIN))
return STR2INT_UNDERFLOW;
if (*end != '\0')
return STR2INT_INCONVERTIBLE;
*out = l;
return STR2INT_SUCCESS;
}
int main(void) {
int i;
/* Lazy to calculate this size properly. */
char s[256];
/* Simple case. */
assert(str2int(&i, "11", 10) == STR2INT_SUCCESS);
assert(i == 11);
/* Negative number . */
assert(str2int(&i, "-11", 10) == STR2INT_SUCCESS);
assert(i == -11);
/* Different base. */
assert(str2int(&i, "11", 16) == STR2INT_SUCCESS);
assert(i == 17);
/* 0 */
assert(str2int(&i, "0", 10) == STR2INT_SUCCESS);
assert(i == 0);
/* INT_MAX. */
sprintf(s, "%d", INT_MAX);
assert(str2int(&i, s, 10) == STR2INT_SUCCESS);
assert(i == INT_MAX);
/* INT_MIN. */
sprintf(s, "%d", INT_MIN);
assert(str2int(&i, s, 10) == STR2INT_SUCCESS);
assert(i == INT_MIN);
/* Leading and trailing space. */
assert(str2int(&i, " 1", 10) == STR2INT_INCONVERTIBLE);
assert(str2int(&i, "1 ", 10) == STR2INT_INCONVERTIBLE);
/* Trash characters. */
assert(str2int(&i, "a10", 10) == STR2INT_INCONVERTIBLE);
assert(str2int(&i, "10a", 10) == STR2INT_INCONVERTIBLE);
/* int overflow.
*
* `if` needed to avoid undefined behaviour
* on `INT_MAX + 1` if INT_MAX == LONG_MAX.
*/
if (INT_MAX < LONG_MAX) {
sprintf(s, "%ld", (long int)INT_MAX + 1L);
assert(str2int(&i, s, 10) == STR2INT_OVERFLOW);
}
/* int underflow */
if (LONG_MIN < INT_MIN) {
sprintf(s, "%ld", (long int)INT_MIN - 1L);
assert(str2int(&i, s, 10) == STR2INT_UNDERFLOW);
}
/* long overflow */
sprintf(s, "%ld0", LONG_MAX);
assert(str2int(&i, s, 10) == STR2INT_OVERFLOW);
/* long underflow */
sprintf(s, "%ld0", LONG_MIN);
assert(str2int(&i, s, 10) == STR2INT_UNDERFLOW);
return EXIT_SUCCESS;
}
Run Code Online (Sandbox Code Playgroud)
基于:https://stackoverflow.com/a/6154614/895245
int atoi(const char* str){
int num = 0;
int i = 0;
bool isNegetive = false;
if(str[i] == '-'){
isNegetive = true;
i++;
}
while (str[i] && (str[i] >= '0' && str[i] <= '9')){
num = num * 10 + (str[i] - '0');
i++;
}
if(isNegetive) num = -1 * num;
return num;
}
Run Code Online (Sandbox Code Playgroud)
你可以编写一点atoi()来获得乐趣:
int my_getnbr(char *str)
{
int result;
int puiss;
result = 0;
puiss = 1;
while (('-' == (*str)) || ((*str) == '+'))
{
if (*str == '-')
puiss = puiss * -1;
str++;
}
while ((*str >= '0') && (*str <= '9'))
{
result = (result * 10) + ((*str) - '0');
str++;
}
return (result * puiss);
}
Run Code Online (Sandbox Code Playgroud)
你也可以让它递归,可以在3行=)
正如已经提到的,atoi
函数系列永远不应该在任何 C 程序中使用,因为它们没有任何错误处理。
该strtol
函数系列是 100% 等效的,但具有扩展功能:它具有错误处理功能,并且还支持十进制以外的其他基数,例如十六进制或二进制。因此正确答案是:使用strtol
(家庭)。
如果您出于某种原因坚持自己手动推出此功能,您应该尝试执行类似的操作,strtol
以防除可选符号和数字之外还存在其他符号。例如,我们想要转换属于较大字符串一部分的数字是很常见的。
具有错误处理支持的原始版本可能如下例所示。此代码仅适用于十进制基数 10 的数字,但其他方面的行为类似于将strtol
可选指针设置为指向遇到的第一个无效符号(如果有)。另请注意,此代码不处理溢出。
#include <ctype.h>
long my_strtol (char* restrict src, char** endptr)
{
long result=0;
long sign=1;
if(endptr != NULL)
{
/* if input is ok and endptr is provided,
it will point at the beginning of the string */
*endptr = src;
}
if(*src=='-')
{
sign = -1;
src++;
}
for(; *src!='\0'; src++)
{
if(!isdigit(*src)) // error handling
{
if(endptr != NULL)
{
*endptr = src;
}
break;
}
result = result*10 + *src - '0';
}
return result * sign;
}
Run Code Online (Sandbox Code Playgroud)
为了处理溢出,可以添加计算字符的代码,并检查它们是否不会超过 10,假设 32 位,long
最多可以是2147483647
10 位数字。
归档时间: |
|
查看次数: |
917635 次 |
最近记录: |