Smokus
Smokus

Reputation: 149

How to convert scanned String via atof() correctly in C?

I need to verify that String passed via scanf() are only numbers and "." and "," should be also acceptable with "-" as a negative number representation. I have written this code:

int main(void)
{
   char cFloatNum[100];
   float fNum;

   scanf("%[[+-]?[0-9]*[.,]?[0-9]+]", &cFloatNum);

   fNum = atof(cFloatNum);

   printf("%f", fNum);

   return EXIT_SUCCESS;
}

I don't know why, but my output always seems to be 0.000000 no matter what numbers I write. I tried testing my regex on various regex website and it matched perfectly.

After writing something to the console, if it's valid it should be printed on the console via printf. For conversion from String to Float, I need to use atof() function.

Examples of valid numbers would be:

-44.276
44,546
56,657675
-77.2435235

Upvotes: 1

Views: 258

Answers (1)

KamilCuk
KamilCuk

Reputation: 141493

only numbers and "." and "," should be also acceptable with "-" as a negative number representation

So write exactly that. For example:

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

int check_your_condition(float *result) {
   int ret = 0;
   *result = 0;
   bool seen_minus = false;
   bool first_character = true;
   bool seen_dot = false;
   float div = 10;
   for (int c; (c = getchar()) != EOF; first_character = false) {
       if (first_character == true && seen_minus == false && c == '-') {
             seen_minus = true;
             continue;
       }
       if (seen_dot == false && (c == '.' || c == ',')) {
             seen_dot = true;
             continue;
       }
       if (!isdigit((unsigned char)c)) {
             ret = -1;
             // TODO handle error properly
             break;
       }
       const short num = c - '0';
       if (seen_dot == false) {
            *result *= 10;
            *result += num;
       } else {
            const float numf = num / div;
            div *= 10;
            *result += numf;
       }
   }
   if (seen_minus) {
       *result *= -1;
   }
   return ret;
}

int main() {
    float a;
    check_your_condition(&a);
    printf("%f\n", a);
}

This is not a "ready to use"(TM) program, as still the newline character on multiple lines is just "ignored" in the input stream (ie. the isdigit(c) will just fail). A proper solution should call ungetc there and include proper logic what to do with the rest of the input.

scanf("%[[+-]?[0-9]*[.,]?[0-9]+]"

is completely wrong. No scanf does not support regexes.

For conversion from String to Float, I need to use atof() function.

Most probably you are asked to read the input as a single line and then apply atof function on the result:

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

int main() {
        char buf[200];
        if (fgets(buf, sizeof(buf), stdin) == NULL) abort();
        errno = 0;
        const float a = atof(buf);
        if (errno) abort();
        printf("%f\n", a);
}

In such solution if . or , will be understood as the decimal separator is locale dependent. And the part of the input string after the string will be just ignored.

Upvotes: 1

Related Questions