Goose
Goose

Reputation: 2250

Incompatible Types in Assignment Between Two Char Arrays

I have a char array that is in hexidecimal format "0d76" and I want to convert it to decimal format but I get an error:

incompatible types in assignment of 'int' to 'char [(((sizetype)(((ssizetype)size) + -1)) + 1)]'

Here is my code:

const char input[] = "0d76";
int size = strlen(input);
char hex_array[size];
for(int i = 0; i < size; i++)
{
   if ('0' <= input[i] && input[i] <= '9') 
   {
       hex_array = input[i] - '0';
   } 
   if ('a' <= input[i] && input[i] <= 'f') 
   {
       hex_array = 10 + (input[i] - 'a');
   } 
   if ('A' <= input[i] && input[i] <= 'F') 
   {
       hex_array = 10 + (input[i] - 'A');
   } 
}

The desired output would be if I entered 0D76 I would get 3446 in decimal format.

Similarly if someone has a better way to convert char arrays from hexadecimal to decimal not using any library functions I would appreciate it.

Upvotes: 1

Views: 1976

Answers (4)

technosaurus
technosaurus

Reputation: 7812

Here is a prematurely optimized example:

int h2i(int c){             /* use bit hacks to hex char -> int */
    if ((unsigned)c-'0'<10) return(c-'0');
    if (((unsigned)c|32)-'a'<6) return(((unsigned)c|32)-'a'+10);
    return -1;
}

int s2i(char *s){
    int i,ret=0;
    while(*s=='0'||*s=='x')*s++;    /* handle 0000ff... and 0xff... */
    while(*s){
        i=h2i(*s);
        if (i==-1) return 0;
        else ret=(ret<<4)|i;
    }
  return ret;
}

char *i2s(int n){
    static char buf[(sizeof(int)<<1)+1]={0};
    int i=0;
    while(i<(sizeof(int)<<1)+1){    /* mask the ith hex, shift it to lsb */
//      buf[i++]='0'+(0xf&(n>>((sizeof(int)<<3)-i<<2))); /* less optimizable ??? */
        buf[i++]='0'+(0xf&((n&(0xf<<((sizeof(int)<<3)-i<<2)))>>((sizeof(int)<<3)-i<<2)));
        if(buf[i-1]>'9')buf[i-1]+=('A'-'0'-10); /* handle A-F */
    }
    for(i=0;buf[i++]=='0';)
        /*find first non-zero*/;
    return (char *)buf+i;
}


#include <stdio.h>
int main(void){
    printf("%s\n",i2s(0xf768cbaf));
    return printf("%X\n",s2i("0xf768cbaf"));
}

Upvotes: 0

unwind
unwind

Reputation: 400159

I'm not ... super convinced about the quality of many of the other answers to this, I'm afraid.

Your basic problem is simple enough: arrays are not assignable objects in C, you can never directly assign to an array.

The secondary problem then becomes how to convert a string in hex to a decimal string. The normal, expected and best way is of course to use library functions, since it's already written, debugged, tested, and well-known to other programmers which helps make your code much more understandable.

If you want to walk in the footprints of the library authors, or just get your hands dirty and do the low-level conversion yourself, that's of course fine. Here's how I would do it, in two steps:

  1. Convert the hexadecimal string to (binary) integer [strtoul() in the library].
  2. Convert the integer to a decimal string [library: snprintf()].

Code:

unsigned long hex_to_ulong(const char *hex)
{
  unsigned long x = 0;

  while(isxdigit((unsigned int) *hex))
  {
    const unsigned int here = tolower((unsigned int) *hex++);
    x *= 16;
    if(isdigit(here))
      x += here - '0';
    else if(here == 'a') /* NOTE: Don't assume anything about the a-f encoding. */
      x += 10;
    else if(here == 'b')
      x += 11;
    else if(here == 'c')
      x += 12;
    else if(here == 'd')
      x += 13;
    else if(here == 'e')
      x += 14;
    else if(here == 'f')
      x += 15;
  }
  return x;
}

And code for the second part generally goes something like this:

/* Create decimal string version of x in the given buffer, returning pointer to
 * the first digit, which is *not* necessarily at out[0].
*/
char * ulong_to_dec(char *out, size_t out_max, unsigned long x)
{
    char *put = out + out_max;
    *--put = '\0';
    do {
      if(put == out)
        return NULL;
      *--put = '0' + (x % 10);
      x /= 10;
    } while(x != 0);
    return put + 1;
}

Then your problem basically becomes:

const char input[] = "0d76";
const unsigned long x = hex_to_ulong(input);
char dec_array[10];
char *dec = ulong_to_dec(dec_array, sizeof dec_array, x);
puts(dec);

NOTE: The above code is untested, and somewhat fiddly so there are probably bugs but you get the idea(s).

Upvotes: 1

Gangadhar
Gangadhar

Reputation: 10526

Here Your implementation is wrong and usage of char array while assigning also

Declare hex_array as integer array

   int hex_array[size]; 


  if ('0' <= input[i] && input[i] <= '9') 
   {
       hex_array[i] = input[i] - '0'; // this converts  , Ascii digit to integer digit
               //^^ make change here
   } 
   if ('a' <= input[i] && input[i] <= 'f') 
   {
       hex_array[i] = 10 + (input[i] - 'a'); // here this convers d==>13   
   } 
   if ('A' <= input[i] && input[i] <= 'F') 
   {
       hex_array[i] = 10 + (input[i] - 'A'); //this convers D ==>13 and assigns to array  
   } 

if you give input

"0D76"

hex_array[0]=0,hex_array[1]=13, hex_array[2]=7,hex_array[4]=6.

Now you have decimal values of hexadecimal characters ,

Now use loop and multiply each value of hex_array with their position values of base 16.

       double decimal=0; 
       int i;
       for(i = 0; i < size; i++)
       decimal=decimal+hex_array[i]*pow(16,size-1-i);

decimal consists , decimal value of hexa decimal input.

Upvotes: 1

Crowman
Crowman

Reputation: 25946

This has probably been asked here a million times, but here's a simple general solution going via an int, using no library functions except tolower() (which you could avoid by insisting either upper or lower case) and strlen() (which is hard to avoid cleanly, and which you use in your code anyway):

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

int st_to_int(char * st, int base);
void int_to_st(int n, char * buffer, int base);
void reverse_string(char * buffer);

int main(void) {
    char input[] = "0D76";

    int n = st_to_int("0D76", 16);
    printf("Hex string '%s' converted to an int is %d.\n", input, n);

    char buffer[100];
    int_to_st(n, buffer, 10);
    printf("%d converted to a decimal string is '%s'.\n", n, buffer);

    int_to_st(n, buffer, 16);
    printf("%d converted to a hex string is '%s'.\n", n, buffer);

    return EXIT_SUCCESS;
}

int st_to_int(char * st, int base) {
    static const char digits[] = {
        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
        'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
        'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
        'u', 'v', 'w', 'x', 'y', 'z'
    };

    int result = 0;

    while ( *st ) {
        result *= base;
        for ( int i = 0; i < (int) sizeof(digits); ++i ) {
            if ( digits[i] == tolower(*st) ) {
                result += i;
                break;
            }
        }
        ++st;
    }

    return result;
}

void int_to_st(int n, char * buffer, int base) {
    static const char digits[] = {
        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
        'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
        'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
        'u', 'v', 'w', 'x', 'y', 'z'
    };

    int i = 0;
    while ( n > 0 ) {
        int next_digit = n % base;
        n = n / base;
        buffer[i++] = digits[next_digit];
    }
    buffer[i] = 0;

    reverse_string(buffer);
}

void reverse_string(char * buffer) {
    int buflen = strlen(buffer) + 1;
    char revbuf[buflen];

    int i;
    for ( i = 0; i < buflen - 1; ++i ) {
        revbuf[i] = buffer[buflen - 2 - i];
    }
    revbuf[i] = 0;

    for ( i = 0; i < buflen; ++i ) {
        buffer[i] = revbuf[i];
    }
}

which gives output:

paul@local:~/src/c/scratch/strconv$ ./strconv
Hex string '0D76' converted to an int is 3446.
3446 converted to a decimal string is '3446'.
3446 converted to a hex string is 'd76'.
paul@local:~/src/c/scratch/strconv$

This code doesn't check for buffer overflows or invalid input (e.g. non-alphanumeric input), left as an exercise. Similarly, it doesn't handle negative numbers or 0. Easy enough to modify, but you wanted to avoid 'intricate/lengthy'.

Upvotes: 0

Related Questions