atoi() 在C++中如何工作

How does atoi() function in C++ work?

本文关键字:何工作 工作 C++ atoi      更新时间:2023-10-16

所以...我知道C++标准库中的 atoi 函数应该将字符串转换为整数......它是如何工作的?...(我正在尝试学习东西,我只是想知道(...如果您能向我展示其中的代码或制作自己的代码来完成相同的任务,将不胜感激......提前谢谢。

像这样:

int atoi( const char *c ) {
    int value = 0;
    int sign = 1;
    if( *c == '+' || *c == '-' ) {
       if( *c == '-' ) sign = -1;
       c++;
    }
    while ( isdigit( *c ) ) {
        value *= 10;
        value += (int) (*c-'0');
        c++;
    }
    return value * sign;
}

您可以循环遍历字符串中的字符,只要它们是数字。对于每个,添加到您保留的计数器中 - 要添加的值是字符的整数值。这是通过从相关数字的 ascii 值中减去 ascii 值"0"来完成的。

请注意,此代码不处理溢出。如果传入"887452834572834928347578423485273"(不适合int(,则结果是未定义的。

逐个数字:

严格来说,char *是指向char的指针。 指针只是指向内存中某个位置的地址。 在 C/C++(和 Java(中,由于 ASCII,字符串由可以单独视为整数(通常为一个字节(的字符组成。

在 C(和 C++(中,指向某种类型的项的指针与指向该类型的元素数组的指针相同。 纯 C 中的字符串只是 char s 的数组,末尾有一个 '' (NUL(,这样你就知道什么时候点击了字符串的末尾,而不必到处传递它的长度(指针只是一个地址,它不知道它指向什么(。

暂时忽略const关键字。

atoi 的 C 版本循环遍历字符串中的每个字符。 *str++做了几件事(了解它是如何工作的很重要,但这是实际编写 C 的一种糟糕的方式(。 相当于*(str++). str++返回 str(指针(的值,然后将其递增 1(但它返回值! *"取消引用"指针,基本上是从内存中读取char。 此char存储在digit中,然后与NUL进行比较。 字符存储在 ASCII 中,ASCII 表示连续的数字,因此我们可以检查digit是否介于 0 和 9 之间。 我们现在知道我们正在读取一个新数字,因此我们将以前的值乘以 10 以"移动"该值,然后添加该数字。

纯C版本:

int atoi(const char* str) {
  int num = 0;
  char digit;
  while ((digit = *str++) != '') {
    if (digit < '0' || digit > '9') {
      return num;  /* No valid conversion possible */
    }
    num *= 10;
    num += c - '0';
  }
  return num;
}

C++字符串是使处理字符串更容易的对象。 您可以使用 .c_str() 从C++字符串中获取char *

C++版本(更可能是对 char* 版本的内联调用,带有"return atoi(str.c_str(((;"(:

int atoi(const std::string& str) {
  int n = 0;
  for (int i = 0; i < str.size(); i += 1) {
    char digit = str.at(i);   /* Could probably use iterator here,
                               * but this is more explicit. */
    if (digit < '0' || digit > '9') {
      return n;  /* No valid conversion possible. */
    }
    n *= 10;
    n += digit - '0';
  }
  return n;
}

编辑:修复了<>无法正确显示的问题。

编辑:添加了C++字符串版本

编辑:已修复,因此123a情况下返回 123。

编辑:将C++版本中的杂散数字更改为n

把问题转过来:你是怎么做到的?当你看到写下的"31"时,你如何理解你需要数出多少个X才能等于它?

    1 * the value in the leftmost column
+  10 * the value in the next column to the right
+ 100 * the value in the next column to the right
...

好吧,你可以编码一下。


实际上,它通常是从最右边的字符实现的,以便于与流一起使用。你会怎么做?

逻辑只是将每个字符处理成它的整数值(调整字符串中的位置(。

这是我在 C# 中是如何做到的。相同的一般想法。

基本上是通过减去 ASCII 零 ('0'( 并检查它是否是数字。您需要知道职位:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int atoi( const char* nptr )
{
    int result   = 0;
    int position = 1;
    const char* p = nptr;
    while( *p )
    {
        ++p;
    }
    for( --p; p >= nptr; p-- )
    {
        if( *p < 0x30 || *p > 0x39 )
        {
            break;
        }
        else
        {
            result += (position) * (*p - 0x30);
            position *= 10;
        }
    }
    result = ((nptr[0] == '-')? -result : result);
    return result;
}
int main()
{
    char buffer[BUFSIZ] = {0};
    printf( "Enter an integer: " );
    fgets( buffer, BUFSIZ, stdin );
    buffer[strlen(buffer)-1] = 0;
    printf( "You entered %dn", atoi( buffer ) );
    return 0;
}

这是一个实现,它还检查错误条件并适用于任何整数类型。

#include <limits>
#include <string>
#include <cctype>
#include <cassert>
#include <type_traits>
template<typename TChar, typename TNumber> bool my_atoi(const std::basic_string<TChar>& str, TNumber& result)
{
    typedef std::make_unsigned<TNumber>::type TNumberUnsigned;
    // check if result type is integer
    assert(std::numeric_limits<TNumber>::is_integer);
    auto currChar = str.cbegin();
    // use corresponding unsigned type to accumulate number to avoid overflows for numbers such as -128
    TNumberUnsigned number = 0;
    bool isNegative = *currChar == '-';
    if (isNegative) {
        // negative numebers can only be parsed into signed types
        if (!std::numeric_limits<TNumber>::is_signed)
            return false;
        ++currChar;
    }
    // empty string or string containing just - sign are not valid integers
    if (currChar == str.cend())
        return false;
    while (currChar != str.cend()) {
        auto digit = *currChar - '0';
        // check that the next digit is valid
        if (digit < 0 || digit > 9)
            return false;
        // check for overflow
        if (number > std::numeric_limits<TNumberUnsigned>::max() / 10)
            return false;
        number *= 10;
        // check for overflow
        if (number > std::numeric_limits<TNumberUnsigned>::max() - digit)
            return false;
        number += digit;
        ++currChar;
    }
    if (isNegative) {
        // correctly check for negative overflow (-128)
        if (number > static_cast<TNumberUnsigned>(std::numeric_limits<TNumber>::max()) + 1)
            return false;
        result = static_cast<TNumber>(-1 * number);
    }
    else {
        if (number > static_cast<TNumberUnsigned>(std::numeric_limits<TNumber>::max()))
            return false;
        result = static_cast<TNumber>(number);
    }
    return true;
}