C++中的atoi()函数是如何工作的?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5710091/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 18:42:41  来源:igfitidea点击:

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

c++

提问by Hymaneown

So...I know that the atoi function in the C++ standard library is supposed to convert a string into an integer...how does it work?...(I'm trying to learn stuff and I was just wondering)...if you could show me the code from it or make your own that would do the same task it'd be greatly appreciated...thanks in advance.

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

回答by Graeme Perrow

Something like this:

像这样的东西:

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;
}

You loop through the characters in the string as long as they are digits. For each one, add to the counter you're keeping - the value to add is the integer value of the character. This is done by subtracting the ascii value of '0' from the ascii value of the digit in question.

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

Note that this code doesn't handle overflow. If you pass in "887452834572834928347578423485273" (which won't fit in an int), the result is undefined.

请注意,此代码不处理溢出。如果您传入“887452834572834928347578423485273”(不适合int),则结果未定义。

回答by Hoa Long Tam

Digit by digit:

逐个数字:

A char *, strictly speaking, is a pointer to a char. A pointer is just an address to some place in memory. In C/C++ (and Java), strings are made up of characters that can, individually, be treated as integers (usually one byte), thanks to ASCII.

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

In C (and C++), a pointer to an item of some type is the same as a pointer to an arrayof elements of that type. Strings in pure C are just arrays of chars, with a '\0'(NUL) at the end so that you know when you've hit the end of a string without having to pass around its length everywhere (a pointer is only an address, it knows nothingabout what it points to).

在 C(和 C++)中,指向某种类型项的指针与指向该类型元素数组的指针相同。纯 C 中的字符串只是chars 的数组,'\0'末尾有一个(NUL) 以便您知道何时到达字符串的末尾而不必到处传递其长度(指针只是一个地址,它知道没有关于它指向什么)。

Ignore the constkeywords for now.

暂时忽略const关键字。

The C version of atoiloops through each character in the string. The *str++does several things (it's important to understand how it works, but it's a horrible way to actually write C). It's equivalent to *(str++). The str++returns the value of str(a pointer) and then increments it by one (but it returns the oldvalue!). The *"dereferences" the pointer, basically reading in a charfrom memory. This charis stored in digitand then compared to NUL. Characters are stored in ASCII, which represents digits contiguously, so we can just check that digitis between 0 and 9. We know now that we're reading in a new digit, so we multiply the previous value by 10 to "shift" the value over and then add in the digit.

C 版本atoi循环遍历字符串中的每个字符。The*str++做了几件事(了解它的工作原理很重要,但实际上编写 C 是一种可怕的方式)。它相当于*(str++). 在str++返回的值str(指针),然后通过一个递增它(但它返回的值!)。的*“解除引用”的指针,在一个基本上读取char从存储器。这char将存储在 中digit,然后与NUL. 字符存储在 ASCII 中,它代表连续的数字,所以我们可以检查它digit在 0 到 9 之间。我们现在知道我们正在读取一个新数字,所以我们将前一个值乘以 10 以“移位”

Pure C version:

纯C版:

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

A C++ string is an object to make dealing with strings easier. You can get a char *from a C++ string with .c_str().

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

C++ version (more likely an inlined call to the char* version with "return atoi(str.c_str());"):

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

    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
...

Edit:Fixed issue where <> would not display properly.

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

Edit:C++ string version added

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

Edit:Fixed so it returns 123 in 123acase.

编辑:已修复,123a以防万一它返回 123 。

Edit:Changed stray num to n in C++ version

编辑:在 C++ 版本中将杂散 num 更改为 n

回答by dmckee --- ex-moderator kitten

Turn the question around: how do youdo it? When you see "31" written down, how do you understand how many of X you need to count out to equal that?

反过来问:是怎么做到的?当您看到写下“31”时,您如何理解需要数出多少个 X 才能等于它?

#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 %d\n", atoi( buffer ) );

    return 0;
}

Well, you can code that up.

嗯,你可以编码。



Actually is is often implemented from the right most character for easy of use with streams. How might you do that?

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

回答by Jonathan Wood

The logic is simply to process each character into it's integer value (adjusting for position within the string).

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

Here'show I did it in C#. Same general idea.

这是我在 C# 中的做法。相同的总体思路。

回答by Jonathan Wood

Basically by subtracting ASCII zero ('0') and checking if it is a digit or not. You need to know the position:

基本上通过减去ASCII零('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;
}

回答by Ghostrider

Here's an implementation that also checks for error conditions and works for any integer types.

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

##代码##