I have a file which stores values like 2.32x7.
I read the floating-point part using:
fscanf(file, "%lf", &value);
It works perfectly... except for when the file stores something like 0x2. In that case, it reads the entire string as a hexadecimal value.
How can I prevent this from happening?
I would like fscanf to just read 0 and ignore x2.
Edit: As suggested by @dbush, I am adding a sample input file.
I am parsing polynomials. So, the input file will be something like:
0x2+2.32x7-4x-9
Reading the line with fgets() and then parsing with crafted code is the most robust.
To read text as a single floating point number with fscanf() up to an 'x', first read with a scanset and then convert.
char buf[400 + 1]; // Something large - consider DBL_MAX may be 1e308
// Scanset of expected FP characters
#define FP_FMT " %400[-+.eE0-9]"
// or maybe simply
#define FP_FMT " %400[^x]"
if (fscanf(FP_FMT, buf) == 1 && sscanf(buf, "%lf", &value) == 1) {
// Success
Pedantic code would use strtod() instead of sscanf(buf, "%lf", &value).
Other consideration include locale use of ',' as the decimal point, NAN, infinity, even wider text as wee exact FP values, how to handle ill formatted text, input errors, EOF, ...
Consider scanning the pair of value and exponent in 1 step.
if (fscanf(FP_FMT "x%d, buf, &power) == 2 && sscanf(buf, "%lf", &value) == 1) {
For your purpose, you should read the full polynomial with fgets() and parse it with as hoc code using strtod() and strtol():
#include <errno.h>
#include <stdlib.h>
int parse_polynomial(struct polynomial *p, const char *s) {
for (;;) {
double factor = 1;
int exponent = 0;
char *p;
while (isspace((unsigned char)*s) {
s++;
}
if (*s == '\0')
break;
if (*s == '+') {
s++;
} else
if (*s == '-') {
factor = -1;
}
if (*s != 'x') {
errno = 0;
factor *= strtod(s, &p);
if (p == s || errno != 0) {
/* parse error */
break;
}
s = p;
}
if (*s == 'x') {
exponent = 1;
s += 1;
if (isdigit((unsigned char)*s) {
unsigned long ul;
errno = 0;
ul = strtoul(s, &p, 10);
if (p == s || errno != 0 || ul > INT_MAX)
break;
exponent = (int)ul;
s = p;
}
}
add_component(p, factor, exponent);
}
return (*s == '\0') ? 0 : -1;
}
❗❗❗ Incorrectly handles numbers with dots...
Thinking, how to fix that.
You can read the numeric characters, then parse number from the string: example
#include <stdio.h>
int main()
{
double value;
char s[32];
*s = 0;
scanf("%31[0-9]", s);
sscanf(s, "%lf", &value);
printf("%f\n", value);
scanf("%3s", s);
puts(s);
}
If you need negative numbers too: example
#include <stdio.h>
int main()
{
double value;
char s[32];
*s = 0;
scanf("%1[-+]", s);
scanf("%30[0-9]", s+!!*s);
sscanf(s, "%lf", &value);
printf("%f\n", value);
scanf("%3s", s);
puts(s);
}
Note that the last code eats the sign even if it's not followed by digits.