-1

I was asked to write a program to find sum of two inputs in my college so I should first check whether the input is valid.

For example, if I input 2534.11s35 the program should detect that it is not a valid input for this program because of s in the input.

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
  • See here, https://stackoverflow.com/questions/15229411/input-validation-of-an-integer-using-atoi – mukunda Jan 16 '19 at 05:18
  • Possible duplicate of [Input validation of an Integer using atoi()](https://stackoverflow.com/questions/15229411/input-validation-of-an-integer-using-atoi) – Andreas Jan 16 '19 at 05:42
  • Carefully review [strtod(3) - Linux manual page](http://man7.org/linux/man-pages/man3/strtod.3.html) *noting* the *"RETURN VALUE"* section and then craft your **validations** to check for each, e.g. `nptr != endptr`, that `errno` is zero and in particular whether `(*endptr && *endptr != '\n')` -- the final telling you that non-digit characters remain after the conversion was completed. – David C. Rankin Jan 16 '19 at 05:47
  • First, we need to know what you mean by “numeric(float)”. If we follow the C definition of floating-point constants, we might accept “digits optional-period digits optional-exponent”, where one of the two “digits” must be non-empty, and the optional exponent is “e optional-sign non-empty-digits” or “E” instead of “e”. We might also accept a hyphen as a minus sign before the number (C does not, in source code, for technical reasons involving the syntax and grammar, but maybe you want to. Or not; we do not know; you need to say.) Maybe you also want to accept hexadecimal floating-point numbers. – Eric Postpischil Jan 16 '19 at 13:49
  • There is also a question of what to do if the input is syntactically a valid number but is mathematically too large (or small) to represent. Do you want to reject that in this code, or perhaps accept it but take its value as infinity or report an error (of size rather than syntax) to the user? – Eric Postpischil Jan 16 '19 at 13:52
  • Numeric(float) means that input may be float but it should be valid for example 3.45638 is valid and 3.4S638 is not (becuase it contains a charecter in it "S") so i want to display this as a erro message – sachin mirajkar Jan 17 '19 at 04:24
  • (a) Can the number have a `-` before it; is `-3` a valid input? (b) Is `3.` a valid input? (c) Is `.3` a valid input? (d) Can the number have an exponent; is `3e4` a valid input? (e) Can the exponent use a capital E instead of lowercase; is `3E4` a valid input? (f) Can the number have an `f` of `F` suffix as in C source code; is `3f` a valid input? (g) Can the number have an `l` or `L` suffix as in C source code; is `3.L` a valid input? (h) Can the number use hexadecimal floating-point format; is `0x3.4a5p-7` a valid input? (i) Are any other forms acceptable? – Eric Postpischil Jan 17 '19 at 04:33
  • thank you for your time sir a) Yes,` -3` is valid. b)No, `3.` is not valid c)Yes, `.3` is valid and should apend a `0` before it d)No, number cannot be exponential e)No f)I am unable to get these points g) this is also I am not getting h) No its only decimal i)As for now only these point I am considering – sachin mirajkar Jan 17 '19 at 06:43
  • sachin mirajkar, Need anything else for an acceptable answer? – chux - Reinstate Monica Dec 21 '19 at 23:58

4 Answers4

2

to check input is numeric(float)

1) Take input as a string char buf[Big_Enough]. I'd expect 160 digits will handle all but the most arcane "float" strings1.

#define N 160
char buf[N];
if (fgets, buf, sizeof buf, stdin) {

2) Apply float strtof() for float, (strtod() for double, strtold() for long double).

  char *endptr;  
  errno = 0;
  float d = strtof(buf, &endptr);
  // endptr now points to the end of the conversion, if any.

3) Check results.

    if (buf == endptr) return "No_Conversion";
    // Recommend to tolerate trailing white-space.
    //   as leading white-spaces are already allowed by `strtof()`
    while (isspace((unsigned char)*endptr) {
      endptr++;
    }
    if (*endptr) return "TrailingJunkFound";
    return "Success";

4) Tests for extremes, if desired.

At this point, the input is numeric. The question remains if the "finite string" an be well represented by a finite float: if a the |result| is in range of 0 or [FLT_TRUE_MIN...FLT_MAX].

This involves looking at errno.

The conversion "succeed" yet finite string values outside the float range become HUGE_VALF which may be infinity or FLT_MAX.

Wee |values| close to 0.0, but not 0.0 become something in the range [0.0 ... INT_MIN].

Since the goal is to detect is a conversion succeeded (it did), I'll leave these details for a question that wants to get into the gory bits of what value.


An alternative is to use fscanf() to directly read and convert, yet the error handling there has its troubles too and hard to portably control.


1 Typical float range is +/- 1038. So allowing for 40 or so characters makes sense. An exact print of FLT_TRUE_MIN can take ~150 characters. To distinguish a arbitrarily "float" string from FLT_TRUE_MIN from the next larger one needs about that many digits.

If "float" strings are not arbitrary, but only come from the output of a printed float, then far few digits are needed - about 40.

Of course it is wise to allow for extra leading/trailing spaces and zeros.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
1

You need to take the input as a string and then, make use of strtod() to parse the input.

Regarding the return values, from the man page:

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

These functions return the converted value, if any.

If endptr is not NULL, a pointer to the character after the last character used in the conversion is stored in the location referenced by endptr.

If no conversion is performed, zero is returned and the value of nptr is stored in the location referenced by endptr.

Getting to the point of detection of errors, couple of points:

  • Ensure the errno is set to 0 before the call and it still is 0 after the call.
  • The return value is not HUGE_VAL.
  • The content pointed to by *endptr is not null and not equal to nptr (i.e., no conversation has been preformed).

The above checks, combined together will ensure a successful conversion.

In your case, the last point is essential, as if there is an invalid character present in the input, the *endptr would not be pointing to a null, instead it would hold the address of that (first) invalid character in the input.

Community
  • 1
  • 1
Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
  • but my consern is to detect that extra charecter and hold it invalid for the program – sachin mirajkar Jan 16 '19 at 06:03
  • @sachinmirajkar yes, you need to check the content of `*endptr` - in case of success, it should point to the terminating null, as there would be nothing left in the input to be converted. In case the conversion failed midway - it will not be pointing to a null character. – Sourav Ghosh Jan 16 '19 at 06:14
  • @saurav Ghosh It would be helpful if you can demostrate with a small example or any reference to find example thank you – sachin mirajkar Jan 16 '19 at 06:26
  • Disagree with [comment](https://stackoverflow.com/questions/54210803/how-to-check-if-input-is-numericfloat-or-it-is-some-character/54211144#comment95248613_54210906) "In case the conversion failed midway - it will not be pointing to a null character " has an exception: `strtof("", &endptr)`. Best to test the `endptr` against `nptr`. – chux - Reinstate Monica Jan 16 '19 at 06:27
  • @chux Just updated the answer to clarify, hope this should be okay now. – Sourav Ghosh Jan 16 '19 at 06:33
  • Better, yet "The return value is not `HUGE_VAL`." is amiss. That concern does not apply when `errno` remains 0. Also `errno == ERANGE` means the conversion worked in that input is numeric, just out of range. Up to OP if that is "valid". – chux - Reinstate Monica Jan 16 '19 at 06:38
  • Also note `errno == ERANGE` and `fabs(result) <= DBL_MIN` can occur. `strtod()` is a mess in the small corners. – chux - Reinstate Monica Jan 16 '19 at 06:39
0
#include<stdio.h>
#include<stdlib.h>
void main(){
char num1[15];
float number1;
int dot_check1=0,check=0,i;
printf("enter the numbers :\n");
gets(num1);
i=0;
while(num1[i]){
    if(num1[i]>'/' && num1[i]<':')
        ;
    else { if(dot_check1==0){
            if(num1[i]=='.')
                dot_check1=1;
            else {
                check=1;
                break;
                }
            }
            else  {
                check=1;
                break;
                }
        }
    i++;
}
if(check){
    printf("please check the number you have entered");
}
else{
    number1=atof(num1);
    printf("you entered number is %f",number1);
}
}
  • i did this any suggession or improvement needed ?\ – sachin mirajkar Jan 16 '19 at 10:05
  • This code has undefined behavior if the input line exceeds 14 characters. (There is almost no proper use of `gets`; do not use it.) This code assumes ASCII, and unnecessarily so, as one could compare with `'0'` and `'9'` or simply use `isdigit` from ``. This code does not recognize numbers with minus signs or exponents. – Eric Postpischil Jan 16 '19 at 13:42
  • as I am a beginner I am not able to understand the above solutions is there any simpler explanation in any article or vedio for reference – sachin mirajkar Jan 16 '19 at 18:04
  • sir I have checked `isdigit` function from `` but it not suitable for me beacuase it only works for `integers` not `float` variables – sachin mirajkar Jan 17 '19 at 06:49
0

Here is untested code to check whether a string meets the requested specification.

#include <ctype.h>


/*  IsFloatNumeral returns true (1) if the string pointed to by p contains a
    valid numeral and false (0) otherwise.  A valid numeral:

        Starts with optional white space.
        Has an optional hyphen as a minus sign.
        Contains either digits, a period followed by digits, or both.
        Ends with optional white space.

    Notes:

        It is unusual not to accept "3." for a float literal, but this was
        specified in a comment, so the code here is written for that.

        The question does not state that leading or trailing white space
        should be accepted (and ignored), but that is included here.  To
        exclude such white space, simply delete the relevant lines.
*/
_Bool IsFloatNumeral(const char *p)
{
    _Bool ThereAreInitialDigits = 0;
    _Bool ThereIsAPeriod = 0;

    //  Skip initial spaces.  (Not specified in question; removed if undesired.)
    while (isspace(*p))
        ++p;

    //  Allow an initial hyphen as a minus sign.
    if (*p == '-')
        ++p;

    //  Allow initial digits.
    if (isdigit(*p))
    {
        ThereAreInitialDigits = 1;
        do
            ++p;
        while (isdigit(*p));
    }

    //  Allow a period followed by digits.  Require at least one digit to follow the period.
    if (*p == '.')
    {
        ++p;
        if (!isdigit(*p))
            return 0;
        ThereIsAPeriod = 1;
        do
            ++p;
        while (isdigit(*p));
    }

    /*  If we did not see either digits or a period followed by digits,
        reject the string (return 0).
    */
    if (!ThereAreInitialDigits && !ThereIsAPeriod)
        return 0;

    //  Skip trailing spaces.  (Not specified in question; removed if undesired.)
    while (isspace(*p))
        ++p;

    /*  If we are now at the end of the string (the null terminating
        character), accept the string (return 1).  Otherwise, reject it (return
        0).
    */
    return *p == 0;
}
Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312