преобразование stringTOint с восьмеричным и гексальным - PullRequest
0 голосов
/ 28 ноября 2018

Я реализовал метод, который преобразует данный массив символов в десятичное целое число.Метод берет каждый символ из массива, вычисляет его десятичное значение и умножает его на 10 ^ n, где n увеличивается с каждой итерацией.

Так, например, массив 4711 будет преобразован следующим образом,1 * 10 ^ 0 + 1 * 10 ^ 1 + 7 * 10 ^ 2 + 4 * 10 ^ 3 = 4711 в качестве десятичного значения.

Теперь у меня вопрос, как расширить функциональность, чтобы stringTOintМетод также может обрабатывать восьмеричные и шестнадцатеричные значения, например, 023 или 0x1A.

/** Converts the given array of characters into a decimal integer */
int stringTOint(char str[]) {
int i, flag, offset, n,base;
flag = 0;
base = 10;
char c = '0';
/*if the first char in the array is '-', the minus flag gets set */
if (str[0] == '-') {
    flag = -1;
}
if (flag == -1) {
    offset = 1;
} else {
    offset = 0;
}
if(offset == 0) {
    if (str[0] == '0' && (str[1] != 'x' && str[1] != 'X') ) {
        base = 8;  // Octal
    } else if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) {
        base = 16; // Hexadecimal
        offset = offset + 2;
    }
}else if(offset == 1) {
    if (str[1] == '0' && (str[2] != 'x' && str[2] != 'X') ) {
        base = 8;  // Octal
    } else if (str[1] == '0' && (str[2] == 'x' || str[2] == 'X')) {
        base = 16; // Hexadecimal
        offset = offset + 2;
    }
}
n = 0;
/*Loop runs until terminating NULL gets found in array */
for (i = offset; str[i] != '\0'; i++) {
    n = n * base + str[i] - c;
}
/*value becomes negative if the negative flag was set */
if (flag == -1) {
    n = -n;
}
/* n gets returned */
return n;
}

Ответы [ 3 ]

0 голосов
/ 28 ноября 2018

Моя идея состояла в том, чтобы проверить текущий символ в массиве, если это десятичное число (так 0-9), или если это буква (так AF), а затем изменить -'0 'на -'A' иесли это буква, и наоборот, если это десятичное число.

for (i = offset; str[i] != '\0'; i++) {
    if(str[i]==/*ABCDEF*/) {
     c = 'A';
} else if( str[i]==/*0123456789*/) {
        c = '0';
    }
    n = n * base + str[i] - c;
}

Но я не уверен, как проверить текущий символ, потому что он должен быть только ОДИН из них, и должно быть лучшезатем сделать 9 операторов if и объединить их с логическим или.

0 голосов
/ 28 ноября 2018

Другой подход - иметь массив допустимых цифр.Используйте strchr для проверки правильности цифры.Если допустимо, разница между указателями - это значение, которое нужно добавить без необходимости вычитать символьные константы.

#include <stdio.h>
#include <string.h>

int stringTOint(char *str, int *number) {
    char *digits = "0123456789";//pointer to string literal
    char *valid = NULL;
    char add = 0;
    int sign = 1;
    int base = 10;

    *number = 0;
    while ( ' ' == *str || '\t' == *str) {
        str++;//skip leading spaces tabs
    }
    if ( '-' == *str || '+' == *str) {
        if ( '-' == *str) {
            sign = -1;
        }
        str++;
    }
    if ( '0' == *str) {
        digits = "01234567";//assign pointer to different string literal
        base = 8;
        str++;
        if ( 'x' == *str) {//lowercase
            digits = "0123456789abcdef";
            base = 16;
            str++;
        }
        if ( 'X' == *str && '0' == *(str - 1)) {//uppercase
            digits = "0123456789ABCDEF";
            base = 16;
            str++;
        }
    }
    while (*str) {//not at terminating zero
        if ( ( valid = strchr ( digits, *str))) {//is a valid digit
            add = valid - digits;//value to add is difference between pointers
            *number = *number * base + add;
            str++;
        }
        else {
            *number = 0;
            return 0;//not a valid digit
        }
    }

    *number = *number * sign;
    return 1;
}

int main ( void) {
    char text[100] = "";
    int value = 0;

    do {
        printf ( "enter an integer\n\t(leading 0 octal or leading 0x hexal)\n\tor enter done\n");
        if ( fgets ( text, sizeof text, stdin)) {
            if ( '\n' == text[0]) {
                break;//exit on empty line
            }
            text[strcspn ( text, "\n")] = 0;//remove newline
            if ( stringTOint ( text, &value)) {
                printf ( "decimal value = %d\n", value);
            }
            else {
                printf ( "\n\tinput problem [%s]\n\n", text);
            }
        }
        else {
            fprintf ( stderr, "fgets EOF\n");
            return 0;
        }
    } while ( strcmp ( text, "done"));//exit if input is done
    return 0;
}

Добавить

    if ( 'b' == *str) {
        digits = "01";//assign pointer to different string literal
        base = 2;
        str++;
    }

перед

    while (*str) {//not at terminating zero

идвоичное значение может обрабатываться с использованием входных данных, таких как b1101

. Чтобы разрешить сочетание верхнего и нижнего регистра в шестнадцатеричных значениях, удалите весь блок if для верхнего регистра, включите ctype.h и измените

if ( 'x' == *str) {

до

if ( 'x' == *str || 'X' == *str) {

и изменить

if ( ( valid = strchr ( digits, *str))) {

на

if ( ( valid = strchr ( digits, tolower ( *str)))) {
0 голосов
/ 28 ноября 2018

Вы не обрабатываете случаи A до F для шестнадцатеричных значений в шестнадцатеричном формате.

   for (i = offset; str[i] != '\0'; i++) {
       int value = (str[i] > ='A' && stri[i]<='F')? (str[i]-'A'+10):(str[i]-'0');
       n = n * base + value;
    }

То есть, если char равен A до F, просто вычтите A из char и добавьте 10, чтобы получить шестнадцатеричное представление в шестнадцатеричном формате.

Примечание: вам необходимо использовать %X или %x для печати в шестнадцатеричном формате.

...