user366312
user366312

Reputation: 17008

How to check a string contains a valid real number

I need to check the 2nd command line argument to see if it's a valid floating point number.

#include <stdio.h>
#include <math.h>

long int fact(int n)
{
    if (n >= 1)
        return n*fact(n - 1);
    else
        return 1;
}

double func(int x0, int n)
{
    int p = 2 * n + 1;

    return (double)pow(x0, p) / (double)fact(p);
}

double sinh_(int x0, int N)
{
    double sum = 0;
    int i = 0;
    for (i = 0; i <= N; i++)
    {
        sum = sum + func(x0, i);
    }

    return sum;
}

double err(int x0, int N)
{
    return abs(sinh(x0) - sinh_(x0, N));
}

int main(int argc, char**argv)
{
    double x0 = 0;
    int N = 0;

    printf("No of args %d\n", argc);

    //if CLA doesn't have exactly 4 arguments passed return -1
    //1st argument is app-name
    //2nd argument is x0
    //4th argument is N
    if (argc >= 3)
    {
        printf("Err: no of arguments should be 2");
        return -1;
    }
    //if the 2nd CLA is not a number, return -1     
    if (!isdigit(atof(argv[1])))
    {
        printf("1st argument must be a real value");
        return -1;
    }
    //if the 3rd CLA is not a number, return -1     
    if (!isdigit(atoi(argv[2])))
    {
        printf("2nd argument must be an int value");
        return -1;
    }

    x0 = atof(argv[1]);
    N = atoi(argv[2]);

    printf("Builtin sinh = %f", sinh(x0));
    printf("Approx sinh = %f", sinh_(x0, N));
    printf("Err value = %f", err(x0, N));
}

Upvotes: 1

Views: 121

Answers (2)

fluter
fluter

Reputation: 13836

atof does not return a status to indicate if the conversion was successful or not, you will need to use strtod for that. Check if endptr is NULL after it returns, also check for any overflow or underflow.

double strtod(const char *nptr, char **endptr);

char *end = NULL;
double x0 = strtod(argv[1], &end);
if (*end) {
      // error, not a valid floating point number
}
if (errno == ERANGE) {
     // error, overflow or underflow
}

Upvotes: 2

Ian Abbott
Ian Abbott

Reputation: 17503

The strto... family of functions such as strtod to convert a string to a double and strtol to convert a string to a long int can give you information about whereabouts in the string the conversion ended.

If the string does not start with optional whitespace followed by a valid number, they will report the conversion ended at the beginning of the string. Otherwise they will report the position of the character that caused the conversion to end. So to check for error, check the position has "moved on" from the beginning of the string, and check the characters at the reported end position.

The functions also check for out-of-range values, setting errno to ERANGE and returning specific values.

The code below checks that the string ends with a null terminator after the number, but in some circumstances, for a string containing multiple separated values, you might want to check for a valid separation character.

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

int main(int argc, char **argv)
{
    double x0;
    long int N;
    char *endptr;

    if (argc != 3)
    {
        fprintf(stderr, "usage: %s x0 N\n", argv[0]);
        return 2;
    }

    errno = 0;
    x0 = strtod(argv[1], &endptr);
    if (endptr == argv[1] || *endptr != '\0')
    {
        fprintf(stderr, "1st argument must be a real value\n");
        return 2;
    }
    if (errno == ERANGE)
    {
        fprintf(stderr, "1st argument out of range\n");
        return 2;
    }

    errno = 0;
    N = strtol(argv[2], &endptr, 10);
    if (endptr == argv[2] || *endptr != '\0')
    {
        fprintf(stderr, "2nd argument must be an integer value\n");
        return 2;
    }
    if (errno == ERANGE)
    {
        fprintf(stderr, "2nd argument out of range\n");
        return 2;
    }

    printf("x0:%g; N:%ld\n", x0, N);
    return 0;
}

I changed the type of N to long int for convenience because there isn't a strtoi function that returns an int.

Upvotes: 1

Related Questions