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

use*_*677 238 c string atoi

我试图找出是否有一种在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)应相当于:

(int) strtol(str, (char **)NULL, 10)
Run Code Online (Sandbox Code Playgroud)

除了错误的处理可能不同.如果无法表示该值,则行为未定义.

  • @NoniA.简洁总是好的,但不以牺牲正确性为代价. (11认同)
  • 没那么错,不安全.atoi()在输入有效时有效.但是,如果你做atoi("猫")怎么办?如果值不能表示为long,则strtol()定义了行为,atoi()没有. (6认同)
  • 这个答案似乎并不比提问者的第一个代码短. (4认同)

AnT*_*AnT 24

不要使用ato...组中的功能.这些都是破碎的,几乎没用.sscanf虽然它也不是完美的,但使用的解决方案会更好.

要将字符串转换为整数,strto...应使用group中的函数.在你的具体情况下,它将是strtol功能.

  • `sscanf`实际上有未定义的行为,如果它试图转换一个超出其类型范围的数字(例如,`sscanf("999999999999999999999","%d",&n)`). (7认同)

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)

GitHub上游.

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

  • 不错的强大`str2int()`.迂腐:使用`isspace((unsigned char)s [0])`. (3认同)

Bis*_*kar 6

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)


jDo*_*ens 5

你可以编写一点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行=)

  • 1) 代码允许 `"----1"` 2) 当结果应该是 `INT_MIN` 时,存在 `int` 溢出的未定义行为。考虑 `my_getnbr("-2147483648")` (2认同)

Lun*_*din 5

正如已经提到的,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最多可以是214748364710 位数字。