Anybody know how I would code an error statement when a user inputs an invalid input.

Discussion in 'C Programming' started by jeff regoord, Sep 11, 2003.

  1. jeff regoord

    jeff regoord Guest

    A user inputs a float value. The scanf() function gets the value.
    However, I need to create an error handler with an if else statement
    saying invalid input if the input is not a number. Does anybody know
    how I could do this?
     
    jeff regoord, Sep 11, 2003
    #1
    1. Advertisements

  2. jeff regoord

    pete Guest

    /* BEGIN new.c */

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

    #define STRINGLENGTH 1000
    #define str(x) # x
    #define xstr(x) str(x)

    int main(void)
    {
    char string[STRINGLENGTH + 1] = {'\0'};
    int rc;

    fputs("Enter a floating point value: ", stdout);
    fflush(stdout);
    rc = scanf("%" xstr(STRINGLENGTH) "[^\n]%*[^\n]", string);
    getchar();
    while (rc) {
    double number;
    char *endptr;

    number = strtod(string, &endptr);
    if (errno) {
    puts("Value out of range.");
    errno = 0;
    } else if (*endptr && !isspace((int)*endptr)) {
    puts("\nI'm sorry Dave. I'm afraid I can't do that.\n");
    } else {
    printf("The number is %f\n", number);
    }
    fputs("Enter a floating point value: ", stdout);
    fflush(stdout);
    rc = scanf("%" xstr(STRINGLENGTH) "[^\n]%*[^\n]", string);
    getchar();
    }
    return 0;
    }

    /* END new.c */
     
    pete, Sep 11, 2003
    #2
    1. Advertisements

  3. Try to be more specific. At the most basic level, you could write

    int ret;
    ...

    input_the_number:
    ret = scanf("%d", &number);

    if (ret != 1) {
    printf("That was not a number; try again!\n");
    goto input_the_number;
    }
    if (number < 0) {
    printf("That was negative; try again!\n");
    goto input_the_number;
    }
    ...


    (Or equivalent stuff with more advanced control-flow structures, but I'm
    too tired to work out where everything would go in a 'while' loop.)

    At a more advanced level, the concept of "error handling" is a pretty
    interesting one. I myself am a fan of the following little function:


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

    static char *Argv0;

    void do_error(const char *fmat, ...);

    int main(int argc, char *argv[])
    {
    Argv0 = argv[0];

    if (0 == 1) {
    do_error("Oh dearie me: %d %d %d\n", 0, 1, 0==1);
    }

    return 0;
    }

    /** This is the interesting bit. */

    void do_error(const char *fmat, ...)
    {
    va_list ap;
    printf("%s: ", Argv0);
    va_start(ap, fmat);
    vprintf(fmat, ap);
    va_end(ap);
    exit(EXIT_FAILURE);
    }


    In case you can't figure it out from the code, the do_error function
    takes a variable number of arguments, just like 'printf', but before
    printing them, it tries to print the name of the executing program,
    and then, once everything is printed, it terminates the program
    directly. This is for those "no recovery possible" sorts of situations,
    which may or may not apply to your problem.

    As you may know, and unlike C++, C does *not* support exception handling
    at the language level. (Anyone got a nice throw/catch sort of idiom for
    standard C? :)

    HTH,
    -Arthur
     
    Arthur J. O'Dwyer, Sep 11, 2003
    #3
  4. jeff regoord

    Kevin Easton Guest

    This might be a good start if you wanted to look into this area...

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

    struct ehandler { jmp_buf env; };

    struct ehandler next_up_handler;

    #define INIT_EXCEPTIONS \
    if (setjmp(next_up_handler.env)) { \
    fprintf(stderr, "Uncaught exception, terminating.\n"); \
    exit(EXIT_FAILURE); \
    }

    #define I_CATCH_EXCEPTIONS volatile int caught;

    #define try { \
    volatile struct ehandler saved_handler = next_up_handler; \
    if (!(caught = setjmp(next_up_handler.env)))

    #define catch \
    next_up_handler = saved_handler; \
    } if (caught) \

    #define throw longjmp(next_up_handler.env, 1)

    /* Exception-throwing version of malloc */
    void *emalloc(size_t s)
    {
    void *r = malloc(s);
    if (!r)
    throw;
    return r;
    }

    int bar()
    {
    throw;

    return 0;
    }

    int foo()
    {
    I_CATCH_EXCEPTIONS
    void * volatile j;

    j = emalloc(100);
    try {
    bar();
    } catch {
    printf("foo caught exception, cleaning up...\n");
    free(j);
    throw;
    }

    printf("foo Normal function execution\n");
    free(j);

    return 0;
    }

    int main()
    {
    I_CATCH_EXCEPTIONS

    INIT_EXCEPTIONS

    try {
    foo();
    } catch {
    fprintf(stderr, "main caught an exception, exiting\n");
    return EXIT_FAILURE;
    }

    printf("program completed normally.\n");

    return 0;
    }

    Obviously if you wanted to make this sort of thing more
    production-quality you'd have to use a consistent namespace for
    identifiers and that sort of thing - perhaps you'd want to allow
    multiple kinds of exceptions too.

    - Kevin.
     
    Kevin Easton, Sep 11, 2003
    #4
  5. jeff regoord

    Kevin Easton Guest

    I wrote:
    [...]
    Come to think of it, it'd be better to put an empty statement in here:

    ; \

    Just in case someone puts a catch immediately after a try without an
    intervening statement. Alternatively it could just be specified that
    there has to be a statement there - there's already other restrictions
    like no return statements inside try blocks.
     
    Kevin Easton, Sep 11, 2003
    #5
  6. jeff regoord

    goose Guest

    I normally do something along the lines of the following coupled with
    returning an error code.

    #define ERROR_CONTINUE(s) \
    fprintf (stderr, "%s:%05i:%s\n", __FILE__, __LINE__, s)

    #define ERROR_FATAL(s,e) \
    (fprintf (stderr, "FATAL ERROR*"), ERROR_CONTINUE(s), exit(e))
    I've done a simplistic try/catch/throw with C using macros
    extensively, but imho it looks very ugly indeed (although it
    works as expected). i also toyed with the idea of doing an
    error reporting mechanism via a few macros and a signal handling
    function, along the lines of

    #define THROW(e) raise(e)

    this of course needs no try/catch statement, the signal handling
    function has to take care of the errors. i found this to be unsuitable
    as well, especially when i need to close files or free memory before
    ending.

    my current method is to write my code as a state machine using
    function pointers:

    struct error_t {
    char *file;
    int line;
    char *mesg;
    };

    struct args_t {
    ...
    };

    typedef int (*fp) (struct error_t *, struct args_t *);

    ....
    int main (void) {
    struct error_t errors;
    struct args_t args;
    fp function_to_run;
    ...
    while (function_to_run!=NULL) {
    if (function_to_run (&errors, &args)) {
    /* handle error here */;
    }
    }
    ...
    }

    unfortunately, this does not lend itself all that well to lots of
    solutions, so i just stick with my first method above of reporting
    file and line number (and error) and then returning values indicating
    success or failure and letting the caller take care of it.

    goose,
     
    goose, Sep 11, 2003
    #6
  7. #include <stdio.h>
    int main( int argc, char *argv[] ) {
    char buffer[128];
    int n;
    double value;
    char ch[2];
    /* Should worry about entering string longer than buffer size,
    * but for simplicity, ignore for now...
    */
    while ( fgets( buffer, sizeof(buffer), stdin) ) {
    n = sscanf( buffer, "%lf%1s", &value, ch );
    if ( n == 1 ) {
    printf( "Number entered: %lf\n", value );
    }
    else {
    printf( "Invalid input\n");
    }
    }
    }
     
    Fred L. Kleinschmidt, Sep 11, 2003
    #7
  8. easy - don't use scanf. Its a dangerous and hard to control function
    with limited error handling. Use fgets and either sscanf or strod.
     
    Mark McIntyre, Sep 11, 2003
    #8
  9. jeff regoord

    jeff regoord Guest


    OK thank you all. Im a novice. How would I make an if else saying
    invalid entry to this program. Maybe no number input
    /* Currency Conversion. User inputs amount of Canadian dollars he or
    she has. The program decides if */
    /* valid entry was input by user. If valid entry occurs. Program
    outputs conversion to U.S dollars */
    /*If there is an invalid entry an error message is ouptut Not a valid
    entry */

    #include <stdio.h>


    float cad = 0.0; /* CAD Canadian Dollar variable */
    float usd = 0.0; /* USD U.S dollar variable */

    int main() /* start main function */

    {

    printf( "\n \n ** Currency Conversion ** \n \n"); /* Print
    name of program */

    printf("Enter number of Canadian Dollars then press enter :
    ");/* Print statement informing user to input number of canadian
    dollars */
    scanf("%f", &cad); /* gets the value entered by user */

    if(cad < 0.0)
    printf("Not a valid entry");
    else
    usd = cad * 0.725415; /* Canadian dollars conversion to
    U.S dollars*/
    printf(" \n Your Canadian dollars are equal to $
    %.2f", usd); /* Output to screen U.S value */
    printf(" in U.S dollars.\n \n");


    return 0; /* Return statement to turn control over to operating
    system */
    }
     
    jeff regoord, Sep 13, 2003
    #9
  10. It's a bad idea to hold monetary data in float. Float is not precise
    enough to hold currencies. What give 1.00 / 0.37 ?
    See what your float will give you. See what you bank will say to it.

    use long or long long instead.
    I type abde
    scanf returns 0 Your program calculates with the last input prior.

    I type -1.3456789
    scanf returns 1 but your program cries invalid number.

    I type e4567

    It will be accepted, even as the input should be 34567 and the user
    had made a typing mistake.

    I type 0.000000000456789
    your program accepts it, even as a currency has only 2 decimal digits.

    What occures with the input 1e3.47b2?

    You have to do pernickety checking the input. None of the functions in
    the standard C library is able to do that.
    As you needs to check the input precise you should use getc() to read
    the input and convert on the fly. The converted result will be fine
    only when the whole line is guilty, else remove anything from the
    input stream until '\n' is found and give an error message to the
    user.

    Use long or long long, calculate cents, not dollars, print out
    dollars.cents
    How precise is the result when someone type 17131713.13?

    Gets you USD 0.0943039 when you tries to convert 0.13 CSD? Should you
    not print 0.09?

    Is 0.1235342274543357e37 a guilty currency member?

    You have some work to print a value that is formatted like a currency
    and not ony a mathematical value. But anyway the result will be really
    worse when you lets a float or double falsyfy the result.

    Do never trust a float/double when you have to calculate commercial.
     
    The Real OS/2 Guy, Sep 13, 2003
    #10
  11. This line is guilty of being Germish (or is it Engman?).

    :)))


    --
    do not write: void main(...)
    do not use gets()
    do not cast the return value of malloc()
    do not fflush( stdin )
    read the c.l.c-faq: http://www.eskimo.com/~scs/C-faq/top.html
     
    Irrwahn Grausewitz, Sep 13, 2003
    #11
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.