Mirel
Mirel

Reputation: 29

Convert hexadecimal numbers to decimal numbers

I have a text file with one line with numbers separated by space as in the following example:

1 -2 3.1 0xf 0xcc

After parsing the file with a C program,the results should be saved in a vector and its internal structure should be:

V[0]=1
V[1]=-2
V[2]=3.1
V[3]=15
V[4]=204

Basically i need to convert the numbers that start with 0x into decimal numbers.

I have tried storing all elements in a char vector and then transform them in numbers but without much succes.

Any help with a piece of code in C will be greatly appreciated.Thanks

Upvotes: 0

Views: 263

Answers (3)

K. Koovalsky
K. Koovalsky

Reputation: 606

What you need is strtol function for integer types. You can use endptr to iterate through the string. For double you can use atof function, but you have to check firstly if the string contains a dot.

EDIT: As user3386109 mentioned strtod is a better solution for double.

Assuming that you have the string in an array:

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

int main()
{
    char numbers_str[] = "1 -2 3.1 0xf 0xcc";
    int ints[10];
    double doubles[10];
    int ints_idx = 0, doubles_idx = 0;

    const char delims[] = " ";
    char *it = strtok(numbers_str, delims);
    while(it != NULL)
    {
        char *dot_it = strchr(it, '.');
        // When a dot is found then a double number is found
        if(dot_it)
            doubles[doubles_idx++] = strtod(it, NULL);
        // When a dot is not found then we've got an integer
        else
            ints[ints_idx++] = strtol(it, NULL, 0);
        it = strtok(NULL, delims);
    }

    printf("Integers found: \n");
    for(int i = 0; i < ints_idx; ++i)
        printf("%d\n", ints[i]);

    printf("Double numbers found: \n");
    for(int i = 0; i < doubles_idx; ++i)
        printf("%f\n", doubles[i]);
}

Upvotes: 1

David C. Rankin
David C. Rankin

Reputation: 84607

The easiest way to handle reading the values from the line is to work your way down the line with strtod. strtod takes two pointers as parameters. The first points to the beginning point to search for digits (or leading +/-) in order to convert the string representation of the number to a numeric value (all leading whitespace is skipped). The second pointer-to-pointer (endptr) will be set to the next character following the last character used in the conversion. You start your search for the next number to convert from there (e.g. set p = ep; and repeat the process).

You can consult the man page for further details, but to validate a successful conversion, you check that the pointer is not equal to the end-pointer (meaning digits were converted) and you check to make sure errno was not set. If there were no digits converted (meaning you had an invalid character), you simply want to scan forward in the line manually until your next +/- or 0-9 is found (or you hit the nul-terminating character).

You want to protect your array bounds and limit the number of values you try and store in your vector array by keeping a simple counter and exiting the loop when your array is full.

Here is a short example (NAN and INF checking omitted):

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

#define VECSZ 5   /* if you need a constant, define one (or more) */

int main (int argc, char **argv) {

    int i, n = 0;
    double v[VECSZ] = {0.0};
    char buf[BUFSIZ] = "";
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!fp) {  /* validate file open for reading */
        fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
        return 1;
    }

    while (n < VECSZ && fgets (buf, BUFSIZ, fp)) { /* read each line */
        char *p = buf, *ep;     /* pointer, end-pointer for strtod  */
        while (n < VECSZ) {     /* convert vales in buf until VECSZ */
            double tmp = strtod (p, &ep);
            if (p != ep) {                  /* digits converted  */
                if (!errno)                 /* validate no error */
                    v[n++] = tmp;           /* add to vector  */
                p = ep;                     /* update pointer */
            }
            else {  /* no digits converted */
                fprintf (stderr, "error: no digits converted.\n");
                /* scan forward to next valid '+,-,0-9' */
                while (*p && *p != '-' && *p != '+' && (*p < '1' || '9' < *p))
                    p++;
                if (*p)         /* numbers remain in line */
                    continue;
                break;          /* otherwise get next line */
            }
        }
    }
    if (fp != stdin) fclose (fp);   /* close file if not stdin */

    for (i = 0; i < n; i++)
        printf ("v[%d]=% g\n", i, v[i]);

    return 0;
}

Example Input File

$ cat dat/strtod_vect.txt
1 -2 3.1 0xf 0xcc

Example Use/Output

$ ./bin/strtod_vect dat/strtod_vect.txt
v[0]= 1
v[1]=-2
v[2]= 3.1
v[3]= 15
v[4]= 204

Look things over and let me know if you have further questions. You can check strtod(3) - Linux man page for further details and error checking that can be done.

Upvotes: 0

babon
babon

Reputation: 3774

You could have a look at sscanf. Here's a bare-bones program. I am sure you can pick up from here:

#include  <stdio.h>

int main(void)
{
    char *hex = "0xF";
    int i= 0;
    sscanf(hex, "%x", &i);
    printf("%d", i);
}

Upvotes: 1

Related Questions