Reputation: 29
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
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
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