简体   繁体   English

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

[英]How does atoi() function in C++ work?

所以...我知道C ++标准库中的atoi函数应该将字符串转换为整数...它是如何工作的?...(我正在努力学习东西,我只是想知道)。 ..如果您可以向我展示其中的代码或制作您自己的代码,那将会非常感激...提前感谢。

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值中减去ascii值'0'来完成的。

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 ),则结果未定义。

Digit by digit: 数字:

A char * , strictly speaking, is a pointer to a char . 严格来说, char *是指向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 . 在C / C ++(和Java)中,字符串由字符组成,这些字符可以单独地被视为整数(通常是一个字节),这要归功于ASCII

In C (and C++), a pointer to an item of some type is the same as a pointer to an array of elements of that type. 在C(和C ++)中,指向某种类型的项的指针与指向该类型的元素数组的指针相同。 Strings in pure C are just arrays of char s, 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 nothing about what it points to). 纯C中的字符串只是char的数组,末尾有一个'\\0' (NUL),这样你就可以知道你何时到达字符串的末尾而不必在任何地方传递它的长度(指针只是一个地址,它对它指向的内容一无所知

Ignore the const keywords for now. 暂时忽略const关键字。

The C version of atoi loops through each character in the string. atoi的C版本循环遍历字符串中的每个字符。 The *str++ does several things (it's important to understand how it works, but it's a horrible way to actually write C). *str++做了几件事(了解它是如何工作的很重要,但实际编写C是一种可怕的方式)。 It's equivalent to *(str++) . 它相当于*(str++) The str++ returns the value of str (a pointer) and then increments it by one (but it returns the old value!). str++返回str (指针)的值,然后将其递增1(但它返回值!)。 The * "dereferences" the pointer, basically reading in a char from memory. * “取消引用”指针,基本上从内存中读取一个char This char is stored in digit and then compared to NUL . char存储在digit ,然后与NUL进行比较。 Characters are stored in ASCII, which represents digits contiguously, so we can just check that digit is 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. 字符以ASCII格式存储,它连续表示数字,因此我们可以检查该digit是否在0到9之间。我们现在知道我们正在读取一个新数字,所以我们将前一个值乘以10来“移位”超过然后加上数字。

Pure C version: 纯C版:

int atoi(const char* str) {
  int num = 0;
  char digit;
  while ((digit = *str++) != '\0') {
    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. C ++字符串是一个更容易处理字符串的对象。 You can get a char * from a C++ string with .c_str() . 您可以使用.c_str()从C ++字符串中获取char *

C++ version (more likely an inlined call to the char* version with "return atoi(str.c_str());"): C ++版本(更可能是使用“return atoi(str.c_str());”来内联调用char *版本:

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

Edit: Fixed issue where <> would not display properly. 编辑:修复了<>无法正确显示的问题。

Edit: C++ string version added 编辑:添加了C ++字符串版本

Edit: Fixed so it returns 123 in 123a case. 编辑:已修复,因此在123a情况下返回123。

Edit: Changed stray num to n in C++ version 编辑:在C ++版本中将stray num更改为n

Turn the question around: how do you do 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?

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

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? 你怎么可能那样做?

The logic is simply to process each character into it's integer value (adjusting for position within the string). 逻辑只是将每个字符处理成它的整数值(调整字符串中的位置)。

Here's how I did it in C#. 这是我在C#中的表现。 Same general idea. 同样的一般想法。

Here's an implementation that also checks for error conditions and works for any integer types. 这是一个实现,它还检查错误条件并适用于任何整数类型。

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

Basically by subtracting ASCII zero ('0') and checking if it is a digit or not . 基本上通过减去ASCII零('0')并检查它是否是一个数字 You need to know the position: 你需要知道这个位置:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM