WedX - журнал о программировании и компьютерных науках

Есть ли способ использовать стандартную библиотеку C для преобразования строки ----> int и отслеживания количества проанализированных символов?

У меня есть вспомогательная функция в моей программе, которая

long parse_int (char * cp, int * i)
{
/* 
    Helper function

    cp: Pointer to a character array that is a base-10 string representation of an integer
     i: Pointer to an integer which will store the output of the parsing of cp

    Returns the number of characters parsed.
*/

    long n = 0;
    *i = 0;
    while (cp!= '\0')
    {
        char c = *cp;
        long k = index_of(digits, c);
        if (k > -1)
        {
            n = n * 10 + k;
        }
        else
        {
            break;
        }
        ++cp;
    }
    return n;
}

где вещи, используемые внутри него

long index_of (char * pc, char c)
{
/*
   Helper function

   pc: Pointer to the first character of a character array
    c: Character to search

   Returns the index of the first instance of
   character c in the character array str. If
   none is found, returns -1.
*/
    char * pfoc = strchr(pc, c); /* Pointer to the first occurrence of character c */
    return pfoc ? (pfoc - pc) : -1;
}

а также

char digits [] = "0123456789";

Если возможно, я хотел бы сократить объем кода, максимально используя огневую мощь стандартной библиотеки. Я полностью осведомлен о atoi, но проблема в том, что я не могу вызвать его и восстановить количество символов, которые он проанализировал при вызове. Какие-либо предложения?

23.02.2015


Ответы:


1

Вы можете использовать strtol(), но вам придется немного поработать, чтобы быть в достаточной безопасности:

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

int strtoi(const char *data, char **endptr, int base)
{
    int old_errno = errno;
    errno = 0;
    long lval = strtol(data, endptr, base);
    if (lval > INT_MAX)
    {
        errno = ERANGE;
        lval = INT_MAX;
    }
    else if (lval < INT_MIN)
    {
        errno = ERANGE;
        lval = INT_MIN;
    }
    if (errno == 0)
        errno = old_errno;
    return (int)lval;
}

Это моя функция strtoi(), которая использует стандартную функцию strtol() для выполнения тяжелой работы. Будьте осторожны (постоянно) не устанавливайте errno в 0, так как ни одна из функций стандартной библиотеки этого не делает. Вы используете его как:

char *end;
int intval = strtoi(str, &end, 0);

Или вы можете быть небрежным и просто использовать:

char *end;
int intval = strtol(str, &end, 0);

Разница возникает, когда строка «субъект» больше, чем помещается в int, но не больше, чем помещается в long; функция strtoi() фиксирует возвращаемое значение в INT_MAX или INT_MIN, но небрежный метод обычно просто дает вам младшие 4 байта любого значения, которое было сохранено в long, что может ввести в заблуждение, если у вас есть 64-битные long и 32-битные int значений.

Обратите внимание, что вызывающий код должен проверять наличие intval == INT_MAX или intval == INT_MIN и errno != 0 для обнаружения переполнения.

Вы можете написать свою функцию parse_int() следующим образом:

long parse_int (char *cp, int *i)
{
    char *end;
    *i = strtoi(cp, &end, 10);  // You want decimal
    return(end - cp);
}
23.02.2015

2

Вероятно, вы захотите использовать strtol вместо atoi. Сигнатура функции для strtol имеет параметр out для указания первого недопустимого (нецифрового) символа)

 long int strtol(const char *nptr, char **endptr, int base);

Тогда вы можете просто сказать следующее:

const char* pszNumber = "8942468XYZ";
char* pszEnd = NULL;
long val = strtol(pszNumber, &pszEnd, 10);

// pszEnd now points to "XYZ"
int number_of_characters_parsed = (int)(pszEnd - pszNumber);
23.02.2015
  • Как работает это вычитание указателя, если pszEnd имеет значение NULL после запуска strtol? 23.02.2015
  • Согласно: linux.die.net/man/3/strtol: If endptr is not NULL, strtol() stores the address of the first invalid character in *endptr. If there were no digits at all, strtol() stores the original value of nptr in *endptr (and returns 0). In particular, if *nptr is not '\0' but **endptr is '\0' on return, the entire string is valid. 23.02.2015
  • Другими словами, я не думаю, что ожидается, что strtol когда-либо установит для endptr значение NULL. Вы наблюдаете что-то другое? Возможно, endptr будет возвращен как NULL, если вы передадите NULL. Но если вы передадите строку, в которой нет недопустимых символов, то endptr укажет на нулевой терминатор в строке. Таким образом, указанный выше pszEnd-pszNumber все еще работает. 23.02.2015

  • 3

    Именно по этой причине семейство функций strtoX считается лучше, чем atoX.

    Вы можете предоставить указатель на переменную, которая получит адрес первого символа, который "не прошел" при преобразовании.

    Количество символов, используемых при преобразовании, представляет собой разницу между этим значением и самой строкой (первым символом). В приведенном ниже коде это будет nextChar - str.

    Например, это один из способов проверить, что целая строка является допустимой длинной:

    char *str = "12345";   // use your own test data here.
    char *nextChar;
    long val = strtol (str, &nextChar, 10);
    if ((nextChar == str) || (*nextChar != '\0')) {
        printf ("Invalid input '%s'\n", str);
        return -1;
    }
    

    Два условия отказа:

    • Следующий символ — это начало строки, символы не использовались, потому что следующий тест фактически допускает пустую строку.
    • Следующий символ не является концом строки, поэтому не все символы были использованы.
    23.02.2015
    Новые материалы

    Как проанализировать работу вашего классификатора?
    Не всегда просто знать, какие показатели использовать С развитием глубокого обучения все больше и больше людей учатся обучать свой первый классификатор. Но как только вы закончите..

    Работа с цепями Маркова, часть 4 (Машинное обучение)
    Нелинейные цепи Маркова с агрегатором и их приложения (arXiv) Автор : Бар Лайт Аннотация: Изучаются свойства подкласса случайных процессов, называемых дискретными нелинейными цепями Маркова..

    Crazy Laravel Livewire упростил мне создание электронной коммерции (панель администратора и API) [Часть 3]
    Как вы сегодня, ребята? В этой части мы создадим CRUD для данных о продукте. Думаю, в этой части я не буду слишком много делиться теорией, но чаще буду делиться своим кодом. Потому что..

    Использование машинного обучения и Python для классификации 1000 сезонов новичков MLB Hitter
    Чему может научиться машина, глядя на сезоны новичков 1000 игроков MLB? Это то, что исследует это приложение. В этом процессе мы будем использовать неконтролируемое обучение, чтобы..

    Учебные заметки: создание моего первого пакета Node.js
    Это мои обучающие заметки, когда я научился создавать свой самый первый пакет Node.js, распространяемый через npm. Оглавление Глоссарий I. Новый пакет 1.1 советы по инициализации..

    Забудьте о Matplotlib: улучшите визуализацию данных с помощью умопомрачительных функций Seaborn!
    Примечание. Эта запись в блоге предполагает базовое знакомство с Python и концепциями анализа данных. Привет, энтузиасты данных! Добро пожаловать в мой блог, где я расскажу о невероятных..

    ИИ в аэрокосмической отрасли
    Каждый полет – это шаг вперед к великой мечте. Чтобы это происходило в их собственном темпе, необходима команда астронавтов для погони за космосом и команда технического обслуживания..


    Для любых предложений по сайту: [email protected]