在 C 语言中如何将字符串转换为整数?

我试图找出是否有一种在C中转换字符串为整数的替代方法。

在我的代码中,我经常使用以下模式。

char s[] = "45";


int num = atoi(s);

那么,有没有更好的办法呢?

1219105 次浏览

在我看来,有strtol更好。我也喜欢strtonum,所以如果你有它就使用它(但记住它是不可移植的):

long long
strtonum(const char *nptr, long long minval, long long maxval,
const char **errstr);

你可能还会对__ABC0和strtoimax感兴趣,它是C99中的标准函数。例如,你可以说:

uintmax_t num = strtoumax(s, NULL, 10);
if (num == UINTMAX_MAX && errno == ERANGE)
/* Could not convert. */

不管怎样,要远离atoi:

调用atoi(str)应该等价于:

(int) strtol(str, (char **)NULL, 10)

,除了错误的处理可能不同。如果不能为 表示为未定义.

.

.

是的,你可以直接存储整数:

int num = 45;

如果你必须解析一个字符串,atoistrol将赢得“最短代码量”比赛。

不要使用ato...组中的函数。这些都坏了,几乎毫无用处。一个稍好的解决方案是使用sscanf,尽管它也不是完美的。

要将字符串转换为整数,应使用strto...组中的函数。在你的特定情况下,它将是strtol函数。

在c++中,你可以使用这样一个函数:

template <typename T>
T to(const std::string & s)
{
std::istringstream stm(s);
T result;
stm >> result;


if(stm.tellg() != s.size())
throw error;


return result;
}

这可以帮助您将任何字符串转换为任何类型,如float, int, double…

你可以编写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);
}

你也可以让它成为递归的,它可以折叠成3行。

健壮的基于C89 __abc0的解决方案

:

  • 没有未定义的行为(就像atoi系列一样)
  • strtol更严格的整数定义(例如,没有前导空格或尾随的垃圾字符)
  • 错误案例的分类(例如,为用户提供有用的错误消息)
  • “testsuite”
#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;
}

GitHub上游

基于:https://stackoverflow.com/a/6154614/895245

这个函数会帮助你

int strtoint_n(char* str, int n)
{
int sign = 1;
int place = 1;
int ret = 0;


int i;
for (i = n-1; i >= 0; i--, place *= 10)
{
int c = str[i];
switch (c)
{
case '-':
if (i == 0) sign = -1;
else return -1;
break;
default:
if (c >= '0' && c <= '9')   ret += (c - '0') * place;
else return -1;
}
}


return sign * ret;
}


int strtoint(char* str)
{
char* temp = str;
int n = 0;
while (*temp != '\0')
{
n++;
temp++;
}
return strtoint_n(str, n);
}

裁判:http://amscata.blogspot.com/2013/09/strnumstr-version-2.html

你可以自己卷!

#include <stdio.h>
#include <string.h>
#include <math.h>


int my_atoi(const char* snum)
{
int idx, strIdx = 0, accum = 0, numIsNeg = 0;
const unsigned int NUMLEN = (int)strlen(snum);


/* Check if negative number and flag it. */
if(snum[0] == 0x2d)
numIsNeg = 1;


for(idx = NUMLEN - 1; idx >= 0; idx--)
{
/* Only process numbers from 0 through 9. */
if(snum[strIdx] >= 0x30 && snum[strIdx] <= 0x39)
accum += (snum[strIdx] - 0x30) * pow(10, idx);


strIdx++;
}


/* Check flag to see if originally passed -ve number and convert result if so. */
if(!numIsNeg)
return accum;
else
return accum * -1;
}


int main()
{
/* Tests... */
printf("Returned number is: %d\n", my_atoi("34574"));
printf("Returned number is: %d\n", my_atoi("-23"));


return 0;
}

这样就可以做你想做的事情,而且不会杂乱。

好吧,我也有同样的问题。我想出了这个解决方案。这对我来说是最有效的。我试过用atoi(),但效果不太好。下面是我的解决方案:

void splitInput(int arr[], int sizeArr, char num[])
{
for(int i = 0; i < sizeArr; i++)
// We are subtracting 48 because the numbers in ASCII starts at 48.
arr[i] = (int)num[i] - 48;
}
//I think this way we could go :
int my_atoi(const char* snum)
{
int nInt(0);
int index(0);
while(snum[index])
{
if(!nInt)
nInt= ( (int) snum[index]) - 48;
else
{
nInt = (nInt *= 10) + ((int) snum[index] - 48);
}
index++;
}
return(nInt);
}


int main()
{
printf("Returned number is: %d\n", my_atoi("676987"));
return 0;
}

只是想分享一个unsigned long的解决方案。

unsigned long ToUInt(char* str)
{
unsigned long mult = 1;
unsigned long re = 0;
int len = strlen(str);
for(int i = len -1 ; i >= 0 ; i--)
{
re = re + ((int)str[i] -48)*mult;
mult = mult*10;
}
return re;
}
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;
}

正如前面提到的,atoi函数家族永远不应该在任何C程序中使用,因为它们没有任何错误处理。

strtol函数族是100%等效的,但具有扩展的功能:它具有错误处理功能,并且还支持十进制以外的其他进制,例如十六进制或二进制。因此,正确答案是:使用strtol (family)。

如果你出于某种原因坚持自己手动展开这个函数,你应该尝试执行类似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;
}

例如,要处理溢出,可以添加计数字符的代码,并检查它们永远不会超过10,假设32位long,最大可以是2147483647, 10位。