Jump to: navigation, search

The C Programming Language, 2nd Edition, by Kernighan and Ritchie
Exercise 2.03 on page 46

Write the function htoi(s) , which converts a string of hexadecimal digits (including an optional 0x or 0X) into its equivalent integer value. The allowable digits are 0 through 9, a through f, and A through F .



Solution by Vidhan Gupta

/* Write the function htoi(s), which converts a s tring of hexadecimal digits
(including an option 0x or 0X) into its equivalent integer value.
The allowable digits are 0 through 9, a throught f, and A through F. */
#include <stdio.h>
#include <string.h>

int htoi(char s[]);
int powerOfHex(int n);
int toUpperCase(int c);

int main()
{
    printf("%d\n", htoi("0x43F2Abc"));
    return 0;
}

int htoi(char s[])
{
    int n = 0, i, j = 0;
    for (i = strlen(s) - 1; i >= 0; --i)
    {
        if (s[i] >= '0' && s[i] <= '9')
            n += (s[i] - '0') * powerOfHex(j);
        else if ((s[i] >= 'A' && s[i] <= 'F') || (s[i] >= 'a' && s[i] <= 'f'))
        {
            if ((s[i] >= 'a' && s[i] <= 'f'))
                n += (toUpperCase(s[i]) - '7') * powerOfHex(j);
            else
                n += (s[i] - '7') * powerOfHex(j);
        }
        else
            i = 0;
        j++;
    }

    return n;
}

int powerOfHex(int n)
{
    int p;
    for (p = 1; n > 0; --n)
        p = p * 16;

    return p;
}

int toUpperCase(int c)
{
    if (c >= 'a' && c <= 'z')
        c -= 'a' - 'A';
    return c;
}
OUTPUT:
71248572

Solution by Richard Heathfield

Here's my solution:

/* Write the function htoi(s), which converts a string of hexadecimal
 * digits (including an optional 0x or 0X) into its equivalent integer
 * value. The allowable digits are 0 through 9, a through f, and
 * A through F.
 *
 * I've tried hard to restrict the solution code to use only what
 * has been presented in the book at this point (page 46). As a
 * result, the implementation may seem a little naive. Error
 * handling is a problem. I chose to adopt atoi's approach, and
 * return 0 on error. Not ideal, but the interface doesn't leave
 * Richard Heathfield much choice.
 *
 * I've used unsigned int to keep the behaviour well-defined even
 * if overflow occurs. After all, the exercise calls for conversion
 * to 'an integer', and unsigned ints are integers!
 */

/* These two header files are only needed for the test driver */
#include <stdio.h>
#include <stdlib.h>

/* Here's a helper function to get Richard Heathfield around the problem of not
 * having strchr
 */

int hexalpha_to_int(int c)
{
  char hexalpha[] = "aAbBcCdDeEfF";
  int i;
  int answer = 0;

  for(i = 0; answer == 0 && hexalpha[i] != '\0'; i++)
  {
    if(hexalpha[i] == c)
    {
      answer = 10 + (i / 2);
    }
  }

  return answer;
}

unsigned int htoi(const char s[])
{
  unsigned int answer = 0;
  int i = 0;
  int valid = 1;
  int hexit;

  if(s[i] == '0')
  {
    ++i;
    if(s[i] == 'x' || s[i] == 'X')
    {
      ++i;
    }
  }

  while(valid && s[i] != '\0')
  {
    answer = answer * 16;
    if(s[i] >= '0' && s[i] <= '9')
    {
      answer = answer + (s[i] - '0');
    }
    else
    {
      hexit = hexalpha_to_int(s[i]);
      if(hexit == 0)
      {
        valid = 0;
      }
      else
      {
        answer = answer + hexit;
      }
    }

    ++i;
  }

  if(!valid)
  {
    answer = 0;
  }

  return answer;
}

/* Solution finished. This bit's just a test driver, so
 * I've relaxed the rules on what's allowed.
 */

int main(void)
{
  char *endp = NULL;
  char *test[] =
  {
    "F00",
    "bar",
    "0100",
    "0x1",
    "0XA",
    "0X0C0BE",
    "abcdef",
    "123456",
    "0x123456",
    "deadbeef",
    "zog_c"
  };

  unsigned int result;
  unsigned int check;

  size_t numtests = sizeof test / sizeof test[0];

  size_t thistest;

  for(thistest = 0; thistest < numtests; thistest++)
  {
    result = htoi(test[thistest]);
    check = (unsigned int)strtoul(test[thistest], &endp, 16);

    if((*endp != '\0' && result == 0) || result == check)
    {
      printf("Testing %s. Correct. %u\n", test[thistest], result);
    }
    else
    {
      printf("Testing %s. Incorrect. %u\n", test[thistest], result);
    }
  }

  return 0;
}

Solution by Marshall S McLeish

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

long hchartoi (char hexdig, int pos);   /* converts a hex char to decimal knowing its 0 based place value */
long htoi (char hexstring[]);               /* converts a string of hex bits to integer ... */

int main(void)
{
  char *endp = NULL;
  char *test[] =
  {
    "F00",
    "bar",
    "0100",
    "0x1",
    "0XA",
    "0X0C0BE",
    "abcdef",
    "123456",
    "0x123456",
    "deadbeef",
    "zog_c"
  };

  long int result;
  long int check;

  size_t numtests = sizeof test / sizeof test[0];

  size_t thistest;

  for(thistest = 0; thistest < numtests; thistest++)
  {
    result = htoi(test[thistest]);
    check = strtol(test[thistest], &endp, 16);

    if((*endp != '\0' && result == -1) || result == check)
    {
      printf("Testing %s. Correct. %ld\n", test[thistest], result);
    }
    else
    {
      printf("Testing %s. Incorrect. %ld\n", test[thistest], result);
    }
  }

  return 0;
}

long htoi (char s[])
{

    char *p = &s[strlen(s)-1];
    long deci = 0, dig = 0;
    int pos = 0;

    while (p >= s) {

        if ((dig = hchartoi(*p, pos)) < 0 ) {
            printf("Error\n");
            return -1;

        }
        deci += dig;
        --p;
        ++pos;

    }
    return deci;
}

/* convert hex char to decimal value */
long hchartoi (char hexdig, int pos)
{

    char hexdigits[] = "0123456789ABCDEF";
    char *p = &hexdigits[0];
    long deci = 0;
    int i;

    while (*p != toupper(hexdig) && deci < 16) {

        ++p;
        ++deci;

    }
    if (*p == toupper(hexdig)) {
       for (i = 0; i < pos; i++)
           deci *= 16;
       return deci;

    }
    return -1;
}


Solution by Pilcrow

/*************************************************
Simple one.
-- Pilcrow
*************************************************/
#include <stdio.h>
#define HEX_LO(N) ((N) >= 'a' && (N) <= 'f')
#define HEX_HI(N) ((N) >= 'A' && (N) <= 'F')
#define HEX_NU(N) ((N) >= '0' && (N) <= '9')
#define IS_HEX(N) (HEX_LO(N) || HEX_HI(N) || HEX_NU(N))

unsigned long htoi(char []);
int main(void)
{
    int i;

    char *test[11] = {
        "F00",
        "bar",
        "0100",
        "0x1",
        "0XA",
        "0X0C0BE",
        "abcdef",
        "123456",
        "0x123456",
        "deadbeef",
        "zog_c"
    };

    for(i =0; i < 11; ++i) {
        printf("%10s %10lu\n",test[i], htoi(test[i]));
    }
    return 0;
}

unsigned long htoi(char hexstr[])
{
    int i;
    long num;
    num = 0;
    i = 0;
    char j;
    if(hexstr[0] == '0' && (hexstr[1] == 'x' || hexstr[1] =='X')) i = 2;

    while(hexstr[i] != '\0') {
        j = hexstr[i];
        if(! IS_HEX(j)) return 0;
        if(HEX_LO(j)) num = num * 16 + 10 + j - 'a';
        else if(HEX_HI(j)) num = num * 16 + 10 + j - 'A';
        else num = num * 16 + j - '0';
        i++;
    }
    return num;
}

Solution by seankndy

#include <stdio.h>
#include <ctype.h>

unsigned long htoi(const char s[]);

int main(void)
{
        printf("%ld\n", htoi("0xFA9C"));
        printf("%ld\n", htoi("0xFFFF"));
        printf("%ld\n", htoi("0x1111"));
        printf("%ld\n", htoi("0xBCDA"));
        return 0;
}

unsigned long htoi(const char s[])
{
        unsigned long n = 0;

        for (int i = 0; s[i] != '\0'; i++) {
                int c = tolower(s[i]);
                if (c == '0' && tolower(s[i+1]) == 'x')
                        i++;
                else if (c >= '0' && c <= '9')
                        n = 16 * n + (c - '0');
                else if (c >= 'a' && c <= 'f')
                        n = 16 * n + (c - 'a' + 10);
        }
        return n;
}

Solution by Octavian

#include <stdio.h>
#include <math.h>

int upperToLower(int character);

int main(void){
        char hexString[10];
        int i, j, c, input, integer;

        char hexadecimals[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
                '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};

        i = 0;
        while ((c = getchar()) != EOF)
        {
                if (c >= 'A' & c <= 'Z')
                {
                        c = upperToLower(c);
                }
                hexString[i] = c;
                ++i;
        }
        hexString[i] = '\0';

        integer = 0;
        for (j = i - 1; j >= 0; --j)
        {
                if(hexString[j] >= 'a' && hexString[j] <= 'z')
                        {

                                for(int k = 0; k < 16; ++k)
                                {
                                        if(hexString[j] == hexadecimals[k])
                                        {
                                                integer = integer + k * pow(16, i-1-j);
                                        }
                                }
                        }
                else
                        integer = integer + (hexString[j] - '0') * pow(16, i-1-j);
        }

        printf("\nThe integer value of the hexadecimal string %s is ", hexString);
        printf("d.\n", integer);
}

int upperToLower(int input){
        int lower;

        lower = input + 'a' - 'A';

        return lower;
}

Solution by Luke Panayi

#include <stdio.h>
#include <ctype.h>
#define BUFFER 1000

int power(int b, int p)
{
	int r=b;

	if (p == 0)
		return 1;

	for (; p > 1; --p)
		r = r*b;

	return r;
}

int ctoi(char c) //take character string of hex number and convert each number into it's respective integer
{
	if (isdigit(c))
		return c - '0';
	else
		return 10 + ((tolower(c) - '0') - 49); //ASCII value of 'a' is 49, 'b' 50 etc
}

int main()
{	
	int i, j, c, n;
	char s[BUFFER];

	for (i=0; i<BUFFER && (c=getchar()) != '\n' && c != EOF; ++i)
	{
		if (c == 'x' && s[i-1] == '0')
		{
			--i;
			--i;
		}
		else
			s[i] = c;
	}

	for (n=0, j=0; j != i; ++j)
		n = n + ctoi(s[j])*power(16, (i-1)-j);

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

	return 0;
}

Solution by i9383

If have suggests welcome tell me

#include <stdio.h>

short isdigit0(char);										/*if is or not digit number '0' '9'*/
short islower0(char);										/*if is or not lower letter 'a' 'f'*/
short isupper0(char);										/*if is or not upper letter 'A' 'F'*/
short hexsymbol0(char s[]);									/*if has or not 0x or 0X symbol*/
int htoi0(char s[]);										/*hexadecimal to integer*/

main()
{
    char s[] = "0Xa1A";

    printf("%d\n", htoi0(s));
    return 0;
}

short isdigit0(char c)
{
    if (c >= '0' && c <= '9')
        return 1;
    else
        return 0;
}

short islower0(char c)
{
    if (c >= 'a' && c <= 'f')
        return 1;
    else
        return 0;
}

short isupper0(char c)
{
    if (c >= 'A' && c <= 'F')
        return 1;
    else
        return 0;
}

short hexsymbol0(char s[])
{
    if (s[0] == '0') {
        if (s[1] == 'x' || s[1] == 'X')
            return 1;
    }
    else
        return 0;
}

int htoi0(char s[])
{
    int  i, d = 0;

    if (hexsymbol0(s))
        i = 2;
    else
        i = 0;
    while (s[i] != '\0') {
        if (isdigit0(s[i]))
            d = d * 16 + s[i] - '0';								/*example
												  123
												  when i == 0 s[i] == '1'
												  0 * 16 + '1' - '0' result is 1
												  when i == 1 s[i] == '2'
												  1 * 16 + '2' - '0' result is 18
												  when i == 2 s[i] == '3'
												  18 * 16 + '3' - '0' result is 291*/
        else if (islower0(s[i]))
            d = d * 16 + 9 + s[i] - 'a' + 1;							/*example
												  2af
												  when i == 1 s[i] == 'a'
												  2 * 16 + 9 + 'a' - 'a' + 1 result is 42
												  when i == 2 s[i] == 'f'
												  42 * 16 + 9 + 'f' - 'a' + 1 result is 687
												  +9 cause before a has 9 numbers
												  +1 cause 'a' - 'a' is 0 need +1 to equal 10
												  cause 'a' is 10*/
        else if (isupper0(s[i]))
            d = d * 16 + 9 + s[i] - 'A' + 1;
        ++i;
    }
    return d;
}

Solution by akiracadet

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

int htoi(char s[]);

int main(void) {
    char s[1000] = "FFF\0";

    printf("%d\n", htoi(s));
}

int htoi(char s[]) {
    int total;
    int power;
    int base;
    int i;

    power = 0;
    base = 16;
    total = 0;
    i = strlen(s);
    printf("%d\n", i);
    while (i >= 0) {
        --i;

        if (s[i] >= '0' && s[i] <= '9') {
            total = (s[i] - '0') * pow(base, power) + total;
        } else if (s[i] >= 'A' && s[i] <= 'F') {
            total = (s[i] - 'A' + 10) * pow(base, power) + total;
        } else if (s[i] >= 'a' && s[i] <= 'f') {
            total = (s[i] - 'a' + 10) * pow(base, power) + total;
        }

        ++power;
    }

    return total;
}

Solution by Miguel Degrossoli

/* Exercise 2-3. Write a function "htoi(s)", which converts a string of
 * hexadecimal digits (including an optional 0x or 0X) into its equivalent
 * integer value. The allawable digits are 0 through 9, a through f, and A
 * through F.
 *
 * I'm using only what's been presented in the book so far.
 *
 * Here the user enters the hex number.
 *
 * I make sure it is valid before calling htoi().
 *
 * It uses some experiences of previous lessons, so the size of the string is
 * twice the number of bytes an integer can hold, because a byte can be
 * represented by two hex digits.
 *
 * I add 1 to the limit, so it can take the trailing '\0'.
 *
 * I may add 2 to the limit, in case the user starts with 0x.
 *
 * I use tolower() from ctype.h, because the book already spoke about it at this
 * point. */

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <limits.h>
#include <ctype.h>

unsigned char getwidth(unsigned long long int max);
unsigned int htoi(char s[]);

int main() {

	int i, c;
	unsigned char lim = getwidth(UINT_MAX) * 2;
	char s[lim + 3];

	for (i = 0; i < lim && (c = getchar()) != '\n' && c != EOF; ++i) {
		
		/* first, lets convert it to lowercase. */
		c = tolower(c);

		/* then, lets check if there's the leading 0x, so we can
		 * increase the limit. */
		if (i == 1 && s[0] == '0' && c == 'x')
			lim += 2;

		/* htoi should convert a good hexadecimal number, so we'll check
		 * before calling it. */
		if (isdigit(c) || (c >= 'a' && c <= 'f') ||
				(i == 1 && s[0] == '0' && c == 'x'))
			s[i] = c;
		else {
			printf("Bad hexadecimal digit: %c.\n", c);
			exit(1);
		}
	}
	
	s[i] = '\0';
	printf("Hexadecimal %s converts to integer %u.\n", s, htoi(s));
	exit(0);
}

/* Retrieves the number of bytes used by a variable type */
unsigned char getwidth(unsigned long long int max) {

	int i;
	
	for (i = 0; pow(2, i) < max; ++i)
		;

	return i;
}

/* Converts a good hexadecimal number to an unsigned integer */
unsigned int htoi(char s[]) {

	int i;
	unsigned int n;

	for (i = 0; s[i] != '\0'; ++i)
		if (i == 1 && s[0] == '0' && s[1] == 'x')
			n = 0;
		else if (isdigit(s[i]))
			n = 16 * n + (s[i] - '0');
		else
			n = 16 * n + (s[i] - 'a' + 10);

	return n;
}

Solution by Marvelcoder

* HexToInt.c
*
*  Created on: 22-Aug-2020
*  Author: Marvelcoder
*  

#include<stdio.h>

 int hexToInt(char []);

 int main(){

    char hex[]="0x6BF0";

     printf("Hexadecimal number %s after conversion is %d",hex,hexToInt(hex));

 return 0;
 }


 int hexToInt(char arr[]){

    int decimal,length,pow,temppow,base,tempbase,num;
    decimal=length=pow=temppow=num=0;

    for(int i=0;arr[i]!='\0';++i){
        length++;
    }

    pow=length-1;

    for(int i=0;i<length;i++){
        temppow=pow;
        tempbase=16;
        base=1;
        while(temppow!=0){
            base=base*tempbase;
            temppow--;
        }
        if(pow==0)base=1;
        if(arr[i]>='0' && arr[i]<='9'){
            num=arr[i]-'0';
        }else if(arr[i]>='A' && arr[i]<='F'){
            num=arr[i]-55;
        }
        decimal+=num*base;
        pow--;
    }

 return decimal;
 }

Solution by KlodElm

#include <ctype.h>
#include <stdio.h>

unsigned int htoi(char s[]);

int main(void)
{
	printf("\n%d\n", htoi("0XFa01B"));
	
	return 1;
}

unsigned int htoi(char s[])
{
	unsigned int i, n = 0;
	
	if (tolower(s[1]) == 'x')
		i = 2;
	else i = 0;
	
	for(; isdigit(s[i]) || (tolower(s[i]) >= 'a' && tolower(s[i]) <= 'f'); ++i)
		if (isdigit(s[i]))
			n = n*16 + s[i] - '0';
		else n = n*16 + tolower(s[i]) + 10 - 'a';
	
	return n;
}

Solution by Nurmareko

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

int htoi(char str[]);
void check_expect(const int a, const int b);
int decimal_value(char symbol, int place_power);
int have_prefix(char str[]);
int valid_hex(char symbol);
int numeric(char c);
int alphabetic_uppercase(char c);
int alphabetic_lowercase(char c);

main() {
	check_expect(htoi(""), -1);
	check_expect(htoi("xyz"), -1);
	check_expect(htoi("@12"), -1);

	check_expect(htoi(""), 0);
	check_expect(htoi("9"), 9);
	check_expect(htoi("a"), 10);
	check_expect(htoi("f"), 15);
	check_expect(htoi("A"), 10);
	check_expect(htoi("F"), 15);
	check_expect(htoi("2f"), 47);
	check_expect(htoi("F00"), 3840);
	check_expect(htoi("123456"), 1193046);

	check_expect(htoi("0x0"), 0);
	check_expect(htoi("0x9"), 9);
	check_expect(htoi("0xa"), 10);
	check_expect(htoi("0xf"), 15);
	check_expect(htoi("0xA"), 10);
	check_expect(htoi("0xF"), 15);
	check_expect(htoi("0x2f"), 47);
	check_expect(htoi("0xF00"), 3840);
	check_expect(htoi("0x123456"), 1193046);

	check_expect(htoi("0X0"), 0);
	check_expect(htoi("0X9"), 9);
	check_expect(htoi("0Xa"), 10);
	check_expect(htoi("0Xf"), 15);
	check_expect(htoi("0XA"), 10);
	check_expect(htoi("0XF"), 15);
	check_expect(htoi("0X2f"), 47);
	check_expect(htoi("0XF00"), 3840);
	check_expect(htoi("0X123456"), 1193046);

	return 0;
}

/* compute the value of string representation of hexadecimal, 
   EXPECT positive value.                                     */
int htoi(char str[]) {
	int exponent, i, power, sum;

	sum = 0;

	if (have_prefix(str)) {
		i = 2;
		exponent = strlen(str) - 3;
	}
	else {
		i = 0;
		exponent = strlen(str) - 1;
	}
	while (str[i] != '\0') {
		if (valid_hex(str[i])) {
			sum += decimal_value(str[i], exponent);
			++i;
			--exponent;
		}
		else
			return -1;
	}
	return sum;
}

/* check for equality between a and b */
void check_expect(const int a, const int b) {
	if (a == b)
		printf("The test passed!\n");
	else
		printf("Actual value %d differs from %d, the expected value.\n", a, b);
}

/* compute (n * 16^e) where n is the decimal value of hexadecimal symbol */
int decimal_value(char symbol, int e) {
	if (numeric(symbol))
		return (symbol - '0') * pow(16, e);
	else if (alphabetic_uppercase(symbol))
		return (symbol - '7') * pow(16, e);
	else if (alphabetic_lowercase(symbol))
		return (symbol - 'W') * pow(16, e);
	else
		return 0;
}

/* is the given string representation of hexadecimal have prefix? */
int have_prefix(char str[]) {
	return (str[0] == '0' && str[1] == 'x' || str[1] == 'X');
}

/* is the given symbol a valid hexadecimal symbol? */
int valid_hex(char symbol) {
	return (numeric(symbol) || alphabetic_uppercase(symbol) || alphabetic_lowercase(symbol));
}

/* is c numeric? */
int numeric(char c) {
	return (c >= '0' && c <= '9');
}

/* is c uppercased alphabetic? */
int alphabetic_uppercase(char c) {
	return (c >= 'A' && c <= 'F');
}

/* is c lowecased alphabetic? */
int alphabetic_lowercase(char c) {
	return (c >= 'a' && c <= 'f');
}

Solution by Foowar

/*
 * exercise 2-3:
 *
 * Write the function htoi(s), which converts a string of hexadecimal digits
 * (including an optional 0x or 0X) into its equivalent integer value.
 * The allowable digits are 0 through 9, a through f, and A through F.
 */
#include <stdio.h>
#include <ctype.h>

int
htoi(const char *s) {
	int i;
	int ret;
	int sign;

	sign = 1;
	i = 0;
	if (s[i] == '-') {
		sign = -1;
		++i;
	} else if (s[i] == '+') {
		++i;
	}

	if (s[i] == '0') {
		++i;
		if (s[i] != 'x' && s[i] != 'X')
			return 0;
		++i;
	}

	for (ret = 0; s[i] != '\0'; ++i) {
		if (s[i] >= '0' && s[i] <= '9') {
			ret = 16 * ret + (s[i] - '0');
		} else if (tolower(s[i]) >= 'a' && tolower(s[i]) <= 'f') {
			ret = 16 * ret + (10 + tolower(s[i]) - 'a');
		} else {
			return 0;
		}
	}

	return ret * sign;
}
Personal tools