2017-01-26 6 views
0

Неисправность, когда требуется более двух цифр ....Программа C для преобразования шестнадцатеричного в целое число

Например. Вход: 0xf Выход: 15
Но вход: 0xFF Выход: -1

char s[20],hexdigit=0,i=0,deci=0; 
scanf("%[^\n]",s); 
if(s[0]=='0' && (s[1]== 'X' || s[1]=='x')) 
    i=2; 
for(;s[i]!='\0';i++){ 

    if(s[i]>='0' && s[i]<='9') 
     hexdigit=s[i]-'0'; 
    else if(s[i]>='a' && s[i]<='f') 
     hexdigit=s[i]-'a'+10; 
    else if(s[i]>='A' && s[i]<='F') 
     hexdigit=s[i]-'A'+10; 
    else 
     break; 
    deci=(16*deci)+hexdigit; 
} 
    printf("\n%d",deci); 
+4

http://ericlippert.com/2014/03/05/how-to-debug-small-programs/ – Biffen

+1

Tha'ts много гольца переменных у вас там ... – John3136

+4

'deci' - это просто' char' - вам нужно сделать его подходящим 'int'. –

ответ

5

Тип char в вашей системе может хранить только значения между -128 и +127. Чтобы получить больший диапазон, используйте другой тип данных.

Вместо

char deci = 0; 

написать

int deci = 0; 

Этот тип также будет переполнение, но гораздо позже. Обычно при 2147483647. Когда вы пытаетесь проанализировать любое большее значение, поведение не определено.

Вы можете пойти один немного дальше, написав

unsigned int deci = 0; 

Этот тип переполнения в 4294967295, после чего он будет снова начать с 0. Нет Неопределенное поведение здесь.

+3

, предлагая использовать неподписанный тип, поскольку код в любом случае читает неотрицательные значения, и это позволит избежать переполнения целых чисел. UB –

+0

Я добавил это предложение. –

+0

Лицо с высокой репутацией набирает репутацию быстро, у меня никогда не было такого большого количества ответов на мой ответ, независимо от того, насколько это было хорошо. –

0

Вы используете char, который может хранить только значения между -128 и +127. Вместо этого используйте другой тип данных, чтобы получить гораздо больший диапазон.

Таким образом, вместо

char deci = 0; 

использование int

int deci = 0; 

и даже если оно переполняет вы можете использовать unsigned int (как код только читает неотрицательные значения)

unsigned int = 0; 

C Standar d гарантирует, что char должен иметь ширину не менее 8 бит, short и int должен быть шириной не менее 16 бит, а long должен иметь ширину не менее 32 бит и sizeof (char) <= sizeof (short) <= sizeof (int) <= sizeof (long) (то же самое верно для неподписанных версий этих типов).

int может быть от 16 до 64 бит в ширину в зависимости от платформы.

Также есть еще одна проблема с кодом, который может привести к ошибке при выполнении в будущем.

Ваш индекс массива i является char и компилятор должен дать вам

Предупреждение: индекс массива имеет тип «символ».

Это указано так, потому что тип char может быть подписан или без знака - это зависит от компилятора. Если подписано char, то возможно, что i будет отрицательным, и в этом случае доступ к индексу отрицательного массива приведет к неопределенному поведению. Я настоятельно рекомендую вам посмотреть на это answer, чтобы избежать общей ошибки в будущем.

Совет: Всегда форматируйте свой код. Правильно, это поможет вам визуализировать, а также другим, кто пытается найти в нем проблемы.

Уход за водоворотом, чтобы объяснить, почему он отказался.

+0

Он не включал unsigned, плюс я нахожу соответствующий текст в документации, чтобы объяснить этот парень ограничениям различных типов данных. –

+0

@RadLexus Он не включал unsigned, плюс я нашел соответствующий текст в документации, чтобы объяснить это ограничение для пользователей различных типов данных –

0

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

Далее вы должны учитывать, что на каждом шаге шестнадцатеричное преобразование потребует базы 16 (так как это перевод шестнадцатеричного) в силу положения.

После этого вы должны определить, как вычитать представление ASCII (только двоичный) от другого так, например:

  1. 'E' - 'А' будет производить 1110 (E) - 1010 (А) = 0100 (4 или десятичное значение вычитания)
  2. Добавьте 10, поскольку десятичной смещения для диапазона АФ: 0100 (Е) + 1010 (10) = 14
  3. Multiply базовой мощности от 16 до заданной позиции (так 0)

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

#include <stdio.h> 
#include <math.h> 
int htoi(char s[]); 
int my_strlen(char s[]); 


int main(int argc, char **argv) { 
    unsigned long int val; 
    val = htoi("0x4E"); //Check N 
    if (val > 0) 
     printf("Value val: %lu", val); 
    else 
     printf("improperly formatted"); 
    return 0; 
} 

//Coded for example 
int htoi(char s[]) { 
    int i, j; 
    unsigned long int z; 
    i = z = 0; 
    j = my_strlen(s) - 1; 

    if(j < 2) return z; 
    if (s[i++] != '0') return z; 
    if (s[i] != 'X' && s[i] != 'x') return z; 

    //Reset i to represent position 
    i = 0; 
    //Convert hexidecimal to integer 
    for(i = 0; s[j] != 'x' && s[j] != 'X'; j--, i++) { 
     if(s[j] >= '0' && s[j] <= '9') 
      z = z + (s[j] - '0') * pow(16, i); 
     else if(s[j] >= 'a' && s[j] <= 'f') 
      z = z + ((s[j] - '0') + 1) * pow(16, i); 
     else if(s[j] >= 'A' && s[j] <= 'F') 
      z = z + ((s[j] - 'A') + 10) * pow(16,i); 
     else 
      continue; 
    } 
    return z; 
} 

//Coded for example 
int my_strlen(char s[]) { 
    int i = 0; 
    while(s[i] != '\0') 
     i++; 
    return i; 
}