Как работает atoi() на С++?

Итак... Я знаю, что функция atoi в стандартной библиотеке С++ должна преобразовывать строку в целое число... как это работает?... (Я пытаюсь изучить материал, и я был просто интересно)... если бы вы могли показать мне код из него или сделать свой собственный, который будет выполнять ту же задачу, это было бы очень полезно... спасибо заранее.

Ответ 1

Что-то вроде этого:

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 '0' из значения ascii соответствующей цифры.

Обратите внимание, что этот код не обрабатывает переполнение. Если вы перейдете в "887452834572834928347578423485273" (который не поместится в int), результатом будет undefined.

Ответ 2

Цифры по цифре:

A char *, строго говоря, является указателем на a char. Указатель - это просто адрес в какое-то место в памяти. В C/С++ (и Java) строки состоят из символов, которые могут индивидуально рассматриваться как целые числа (обычно один байт), благодаря ASCII.

В C (и С++) указатель на элемент некоторого типа такой же, как указатель на массив элементов этого типа. Строки в чистом C - это просто массивы char s, с '\0' (NUL) в конце, чтобы вы знали, когда попадете в конец строки, не обойдя всю ее длину (указатель только адрес, он ничего не знает о том, на что он указывает).

Игнорировать ключевые слова const.

Версия C atoi выполняет цикл каждого символа в строке. *str++ делает несколько вещей (важно понять, как это работает, но это ужасный способ писать C). Это эквивалентно *(str++). str++ возвращает значение str (указатель), а затем увеличивает его на единицу (но возвращает старое значение!). * "разыгрывает" указатель, в основном читающий в char из памяти. Этот char хранится в digit, а затем сравнивается с NUL. Символы хранятся в ASCII, который представляет цифры смежно, поэтому мы можем просто проверить, что digit находится между 0 и 9. Мы знаем теперь, что мы читаем новую цифру, поэтому мы умножаем предыдущее значение на 10 на "сдвиг" "значение над, а затем добавить в цифру.

Версия Pure 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;
}

Строка С++ - это объект, облегчающий работу со строками. Вы можете получить char * из строки С++ с помощью .c_str().

Версия на С++ (скорее всего, встроенный вызов версии 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;
}

Изменить: Исправлена ​​проблема, когда < > не отображалась должным образом.

Изменить: Добавлена ​​версия строки в С++

Изменить: Исправлено, так что он возвращает 123 в 123a случае.

Изменить: Изменено число без изменений в версии С++

Ответ 3

Поверните вопрос: как вы это делаете? Когда вы видите "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
...

Ну, вы можете это исправить.


На самом деле это часто реализуется с самого правого персонажа для удобного использования с потоками. Как вы можете это сделать?

Ответ 5

Мы используем atoi() для преобразования числовой строки в свое целочисленное значение. Это функция библиотеки c. Он принимает строку в качестве аргумента и возвращает целое значение.

В приведенном ниже примере я описываю метод для реализации собственной функции atoi.

#include<stdio.h>
#include<stdint.h>

/*Macro to check numeric character*/
#define Is_NUMERIC_STRING(d) (*(char*)d >= 48) && (*(char*)d<= 57)


uint32_t
StringToInt(const char *pszBuffer) {

uint32_t u32Number=0;

while( Is_NUMERIC_STRING(pszBuffer)) { //Loop terminate When alphabetic character occur.     

u32Number=(u32Number*10)+ (*pszBuffer-48);
pszBuffer++;
}

return u32Number;
}

int main() {
uint32_t d;

d=StringToInt("1230");

printf("%u\n",d);

return 0;
}

Для получения дополнительной информации вы можете увидеть эту ссылку: http://www.aticleworld.com/

Note: This code is only for the string whose value within the range of integer.

Ответ 6

В основном, вычитая 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 %d\n", atoi( buffer ) );

    return 0;
}

Ответ 7

Здесь реализована реализация, которая также проверяет условия ошибки и работает для любых целых типов.

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