Почему я получаю этот неожиданный результат, используя atoi() в C?

Я не понимаю результаты следующего кода C.

main()
{
    char s[] = "AAA";
    advanceString(s);
}

void advanceString(p[3])
{
    int val = atoi(p);
    printf("The atoi val is %d\n",val);
}

Здесь значение atoi отображается как 0, но я не мог точно определить причину. По моему пониманию, это должно быть суммирование десятичных эквивалентов каждого значения в массиве? Пожалуйста, поправьте меня, если я ошибаюсь.

Ответ 1

atoi() преобразует строковое представление целого в его значение. Он не будет преобразовывать произвольные символы в их десятичное значение. Например:

int main(void)
{
    const char *string="12345";

    printf("The value of %s is %d\n", string, atoi(string));

    return 0;
}

В стандартной библиотеке C нет ничего, что преобразует "A" в 65 или "Z" на 90, вам нужно будет написать это самостоятельно, в частности, для любой кодировки, которую вы ожидаете в качестве входных данных.

Теперь, когда вы знаете, что делает atoi(), , не используйте его для обработки числового ввода в том, что вы придумали. Вам действительно нужно иметь дело с тем, что вы не ожидаете. Хм, что происходит, когда я вхожу 65 вместо А? Учителя любят нарушать вещи.

atoi() не выполняет никаких проверок ошибок, что делает все, что полагается на него, для преобразования произвольного входного хрупкого в лучшем случае. Вместо этого используйте strtol() (пример с помощью POSIX):

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

int main(void)
{
    static const char *input ="123abc";
    char *garbage = NULL;
    long value = 0;

    errno = 0;

    value = strtol(input, &garbage, 0);

    switch (errno) {
        case ERANGE:
            printf("The data could not be represented.\n");
            return 1;
        // host-specific (GNU/Linux in my case)
        case EINVAL:
            printf("Unsupported base / radix.\n");
            return 1;
    }

    printf("The value is %ld, leftover garbage in the string is %s\n",
           // Again, host-specific, avoid trying to print NULL.
           value, garbage == NULL ? "N/A" : garbage);

    return 0;
}

При запуске это дает:

Значение - 123, оставшийся мусор в строка abc

Если вы не заботитесь о сохранении/просмотре мусора, вы можете установить второй аргумент NULL. Нет необходимости free(garbage). Также обратите внимание: если вы передаете 0 в качестве третьего аргумента, предполагается, что вход является желаемым значением десятичного, шестнадцатеричного или восьмеричного представления. Если вам нужен радиус 10, используйте 10 - он будет терпеть неудачу, если вход не такой, как вы ожидаете.

Вы также проверите возвращаемое значение для максимального и минимального значения, которое может обрабатывать a long int. Тем не менее, если либо возвращаются для указания ошибки, устанавливается errno. Упражнение для читателя состоит в изменении *input от 123abc до abc123.

Важно проверить возврат, так как ваш пример показывает, что произойдет, если вы этого не сделаете. AbcDeFg не является строковым представлением целого числа, и вам нужно иметь дело с этим в своей функции.

Для вашей реализации самым основным советом, который я могу вам дать, будет серия переключателей, что-то вроде:

// signed, since a return value of 0 is acceptable (NULL), -1
// means failure
int ascii_to_ascii_val(const char *in)
{
    switch(in) {
        // 64 other cases before 'A'
        case 'A':
           return 65;
        // keep going from here
        default:
            return -1; // failure

}

.. то просто запустите это в цикле.

Или, предварительно заполнить словарь, чтобы функция поиска могла обладать (лучше). Вам не нужны хеши, просто хранилище ключей → , поскольку вы знаете, что он собирается содержать заранее, где стандартные символы ASCII являются ключами, а их соответствующие идентификаторы - значениями.

Ответ 2

Он пытается преобразовать строку в целое число. Поскольку AAA не может быть преобразовано в целое число, значение равно 0. Попробуйте дать ему 42 или что-то еще.

Если действительное преобразование не может быть выполняется, возвращается нулевое значение.

См. http://www.cplusplus.com/reference/clibrary/cstdlib/atoi/

Ответ 3

Прочитайте atoi() как a для я (ASCII для целого).

atoi() преобразует строку, представляющую десятичное число, в целое число.

char s[] = "42";
int num = atoi(s); //The value of num is 42.

Ответ 4

atoi ожидает, что его аргумент будет строковым представлением десятичной (base-10) целочисленной константы; AAA не является допустимой десятичной целочисленной константой, поэтому atoi возвращает 0, потому что у него нет другого способа указать, что вход недействителен.

Обратите внимание, что atoi преобразует до первого символа, который не является частью действительной целочисленной константы; другими словами, "123" и "123w" оба будут преобразованы в 123.

Как и все остальные, не используйте atoi; вместо этого используйте strtol.