Thread: Number user input

  1. #16
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by jimtuv View Post
    So using atoi and validating the input using isdigit the way I did is a mistake??? I can see that strtol is great for conversions from other bases but what is the advantage here?? And how do I handle the validation.
    atoi doesn't handle underflow/overflow, among others.
    strtol contains sophisticated and powerful parsing of numbers. Probably better than your own. Plus it's only a few lines. Much fewer than your solution. I'd say those are the advantages.

    I am totally unfirmilliar with errno though if I remember I read something about that a few days ago. I would have to #include <errno.h> and then on a failure return code from strol check the value that is in errno for what type of error it was correct? This would be only necessary if I were going to do something specific after an error. Otherwise I could just force reentry of the data on an error from strol and then checking errno would be unnecessary.
    That pretty much sums it up.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  2. #17
    Registered User jimtuv's Avatar
    Join Date
    May 2010
    Location
    Sylvania, Ohio
    Posts
    94
    Ok here is my try at this. I think I understand what is going on pretty well. It seems to work and your right it's much smaller. I can dump the Validate function completely. I hope this is the right way to do this.



    Code:
    long int InputNext(int min, int max){
    
        char buffer[BUFSIZ];    
        char* pEnd;
        long int input;
    
        errno = 0;
       
        printf(CURSOR);
    
        while(errno != 42 ||
                errno == ERANGE ||
                *pEnd != '\0' ||
                input == 0 && buffer[0] != '0')
        {
           if ( fgets(buffer, sizeof buffer, stdin) != NULL ){
               buffer[strlen(buffer) -1] = '\0';
               input = strtol(buffer,&pEnd,10);            
           }
           printf(CURSOR);
        }
        return input;
    }

  3. #18
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    If it works, so much the better, but people probably wont know what 42, the meaning of life, the universe, and everything, has to do with numerical input. (It actually corresponds to an illegal byte sequence in MinGW32, now that I look it up, but I can't say that's relevant. EINVAL is the only other err code besides ERANGE that matters.) Not to mention you de-reference pEnd before it points somewhere.

    I don't know how long you've been coding, but you can stick to any line reading convention that you know. It's a lot easier to define the loop in terms of success as well.

    Code:
    while(fgets(buffer, sizeof buffer, stdin) != NULL)
    {
       errno = 0;
       input = strtol(buffer, &pEnd, 10);
       if(*pEnd == '\n' && errno == 0) 
       {
          break;
       }
    }
    Not that you can't fix what you have.

  4. #19
    Registered User jimtuv's Avatar
    Join Date
    May 2010
    Location
    Sylvania, Ohio
    Posts
    94
    LOL When I realized it returned 42 I chuckled a bit thinking Dennis Ritchie might have stuck a "Hitch-hiker's Guide to the Galaxy" reference in.

    I am pretty green I started learning C on 05/01/2010 so only been at it a little while. I am going pretty slowly to insure I understand before moving on.

    Not to mention you de-reference pEnd before it points somewhere.
    Ooops! I was caught up in making the condition and didn't even notice that. I will need to be more careful and write out the algorithms first rather then building things trial and error as I have been doing.

    It's a lot easier to define the loop in terms of success as well.
    I had actually considered this first but went with the second guess. I should listen to my instincts more often.

  5. #20
    Registered User jimtuv's Avatar
    Join Date
    May 2010
    Location
    Sylvania, Ohio
    Posts
    94
    Here is the fixed code. As I am going to use this for menus I need to add in the min and max values and not allow the user to just hit enter without entering something.

    Code:
    long int InputNext(int min, int max){
    
        char buffer[BUFSIZ];    
        char* pEnd;
        long int input;     
        
        printf(CURSOR);
    
        while (fgets(buffer, sizeof buffer, stdin) != NULL){
            errno = 0;
            printf("in loop\n");
            input = strtol(buffer,&pEnd,10);
            if ( *pEnd == '\n' && errno == 0
                               && input >= min
                               && input <= max
                               && buffer [0] != '\n'){
                 break;
            }
            printf(CURSOR);
        }
        return input;
    }
    My question here is; in a complex conditional as I have above is this a good way to write this code style wise. To me lining up the &&'s makes it very readable.

  6. #21
    Registered User
    Join Date
    May 2010
    Location
    Naypyidaw
    Posts
    1,314
    I better get some sleep before commenting on your code.

  7. #22
    Registered User jimtuv's Avatar
    Join Date
    May 2010
    Location
    Sylvania, Ohio
    Posts
    94
    I had to see if I could figure out how to do floating point number input from the above code and it was very simple. All I had to do is use strtod instead of strtol. They are a little different (only the base part). It's easier than I thought it would be. I just learned about arrays and pointer so using both was a bit intimidating. It took me a little bit to understand exactly what everything was doing. It is really cool how pEnd keep track of where it stopped.

    here is the code for the floating point version.

    Code:
    double InputFloat(double min, double max){
    
        double input;
        char buffer[BUFSIZ];
        char* pEnd;
    
        printf(CURSOR);
    
        while (fgets(buffer, sizeof buffer, stdin) != NULL){
            errno = 0;
            input = strtod(buffer,&pEnd);
            if ( *pEnd == '\n' && errno == 0
                               && input >= min
                               && input <= max
                               && buffer[0] != '\n' ){
                break;
            }
            printf(CURSOR);
        }    
        return input;
    }

  8. #23
    Registered User
    Join Date
    May 2010
    Location
    Naypyidaw
    Posts
    1,314
    if fgets() returns NULL(hit EOF), you are returning garbage.

  9. #24
    Registered User jimtuv's Avatar
    Join Date
    May 2010
    Location
    Sylvania, Ohio
    Posts
    94
    Quote Originally Posted by Bayint Naung View Post
    if fgets() returns NULL(hit EOF), you are returning garbage.
    Yep forgot that input is not initialized until inside the while loop. If it fgets returns Null then input is uninitialized and thus undefined. So yes it would return garbage.

    Here is my first thought of fixing it. If I initialize input to below min value and then run a do while loop in the call to InputFloat checking for a less then min value it should work.

    Here is the call

    Code:
        printf("Enter a number for InputFloat (%f to %f)\n", min, max);         
        do {
            nfnumber = InputFloat(min, max);
        }
        while ( nfnumber < min );
    and in the function

    Code:
    double InputFloat(double min, double max){
    
        double input;
        char buffer[BUFSIZ];
        char* pEnd;
        input = min - 1;
    
        printf(CURSOR);
    
        while (fgets(buffer, sizeof buffer, stdin) != NULL){
            errno = 0;
            input = strtod(buffer,&pEnd);
            if ( *pEnd == '\n' && errno == 0
                               && input >= min
                               && input <= max
                               && buffer[0] != '\n' ){
                break;
            }
            printf(CURSOR);
        }    
        return input;
    }
    Last edited by jimtuv; 06-08-2010 at 10:37 PM.

  10. #25
    Registered User
    Join Date
    May 2010
    Location
    Naypyidaw
    Posts
    1,314
    User enter something invalid (say number gt max) then for 2nd try,user hits EOF.
    so input > max; and you are returning some value greater than max
    What a superuser!
    Last edited by Bayint Naung; 06-08-2010 at 10:47 PM. Reason: spelling warning

  11. #26
    Registered User jimtuv's Avatar
    Join Date
    May 2010
    Location
    Sylvania, Ohio
    Posts
    94
    Code:
    double InputFloat(double min, double max){
    
        double input;
        char buffer[BUFSIZ];
        char* pEnd;
        input = min -1;
    
        printf(CURSOR);
    
        while (fgets(buffer, sizeof buffer, stdin) != NULL){
            errno = 0;
            input = strtod(buffer,&pEnd);
            if ( *pEnd == '\n' && errno == 0
                               && input >= min
                               && input <= max
                               && buffer[0] != '\n' ){
                break;
            }
            printf(CURSOR);
            input = min -1;
        }    
        return input;
    }

  12. #27
    Registered User jimtuv's Avatar
    Join Date
    May 2010
    Location
    Sylvania, Ohio
    Posts
    94
    I realize I am still way over my brain damaged head trying to get a stupid number from a user.

    I will have to pick this apart piece by piece. I am determined to understand this.

  13. #28
    Registered User jimtuv's Avatar
    Join Date
    May 2010
    Location
    Sylvania, Ohio
    Posts
    94
    Here is my next attempt at this. I tried to handle everything I could think of. I temporarily set

    Code:
    char buffer[10];
    and tried to overrun it with 123456789. It truncated it to 12345678 and I added a stdin clearing part
    Code:
    while(getchar()!='\n');
    to handle the leftovers.

    Here is the revise code
    Code:
    /* 
     * File:   inputnumber.c
     * Author: jim
     *
     * Created on June 9, 2010, 11:09 AM
     */
    
    /* *******************************************************
    * Testbed for number input routines
    *************************************************************/
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <errno.h>
    
    #define MIN -100
    #define MAX 100
    
    #define CURSOR ">>>"
    
    long int InputNumber(int min, int max);
    
    int main(void){
    
        long int number;
    
    
        printf("Enter a number (%d to %d)\n",MIN,MAX);
        number = InputNumber(MIN,MAX);
    
        printf("The number you entered = %ld\n",number);
        
        
        return 0;
    }
    
    long int InputNumber(int min, int max){
    
        int i;
        char buffer[BUFSIZ];
        char* pEnd;
        long int input;    
    
        do{
            input = 0;
            printf(CURSOR);
            for ( i = 0; i < sizeof buffer; i++){
                 buffer[i] = 0;
            }
            while (fgets(buffer, sizeof buffer, stdin) != NULL){
    
                errno = 0;
                buffer[strlen(buffer)-1] = '\0';
                input = strtol(buffer,&pEnd,10);
                if (*pEnd == '\0' && errno == 0){
                    break;
                }
                else if ( errno == ERANGE ){
                    input = 0;
                    for ( i = 0; i < sizeof buffer; i++){
                        buffer[i] = 0;
                    }
                }
                printf(CURSOR);
            }
            if ( strlen(buffer) >= (sizeof buffer - 2) ){
                while(getchar()!='\n');
            }
        }
        while (input < min || input > max);
        return input;
    }
    Last edited by jimtuv; 06-09-2010 at 10:44 PM.

  14. #29
    Registered User
    Join Date
    May 2010
    Location
    Naypyidaw
    Posts
    1,314
    You are making it unnecessarily complicated again.

  15. #30
    Registered User jimtuv's Avatar
    Join Date
    May 2010
    Location
    Sylvania, Ohio
    Posts
    94
    Complexity seems to be my downfall.

    My son asked what if the user wanted to know why they are being asked for input again instead of just a new cursor. So I added some error messages and a way to turn them on or off if desired.

    Code:
    /* 
     * File:   inputnumber.c
     * Author: jim
     *
     * Created on June 9, 2010, 11:09 AM
     */
    
    /* *******************************************************
    * Testbed for number input routines
    *************************************************************/
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <errno.h>
    
    #define MIN -100
    #define MAX 100
    #define EXTRA 1
    #define VERBOSE_ON 1
    #define VERBOSE_OFF 0
    
    #define CURSOR ">>>"
    
    long int InputNumber(int min, int max, int verbose);
    void ClearBuf(void);
    
    int main(void){
    
        long int number;
    
    
        printf("Enter a number (%d to %d)\n",MIN,MAX);
        number = InputNumber(MIN,MAX,VERBOSE_ON);
    
        printf("The number you entered = %ld\n",number);
        
        
        return 0;
    }
    
    long int InputNumber(int min, int max, int verbose){
    
        int i;
        char buffer[BUFSIZ];
        char* pEnd;
        long int input;
    
    
        do{
            // Making sure that buffer is empty when looped
            // not sure if I need to do this
            for (i = 0; i < sizeof buffer; i++){
                buffer[i] = 0;
            }
    
            // Make sure that all the values are 0 when looped
            errno = 0;
            input = 0;
            printf(CURSOR);
    
            if (fgets( buffer,sizeof buffer ,stdin)!= NULL){
                input = strtol(buffer,&pEnd,10);
                if ( buffer[0] != '\n' && *pEnd == '\n' || *pEnd == '\0'){
                   // do something if successful stub
                   // not necessary but could be useful in some circumstances
                }
                else {
                    if ( input == 0 && buffer[0] == '\n'){
                        if (verbose == VERBOSE_ON) printf("You just hit return Please enter a number first!\n");
                    }
                    else if(input == 0 && *pEnd != '\n'){
                        if (verbose == VERBOSE_ON) printf("You entered letters not numbers!\n");
                    }
                    else
                        if (verbose == VERBOSE_ON) printf("You added %s",pEnd);
    
                    // This is to make it loops if there is extra data
                    // also when number to large reset input from junk
                    if(errno != ERANGE) errno = EXTRA;
                    if(errno == ERANGE) input = 0;
                }         
            }        
            if (errno == ERANGE)
                if (verbose == VERBOSE_ON) printf("The number is to large!\n",input);
            if (input < min || input > max && errno != ERANGE)
                if (verbose == VERBOSE_ON) printf("Your input %ld is out of range %d to %d\n",input,min,max);
            
        }
        while ( input < min || input > max ||errno == ERANGE || errno == EXTRA);
        
        return input;
    }

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. How to limit user input to a certain number of digits?
    By NewbGuy in forum C Programming
    Replies: 7
    Last Post: 05-08-2009, 09:57 PM
  2. Program that requests input of an integer number
    By theejuice in forum C Programming
    Replies: 6
    Last Post: 04-30-2008, 02:18 AM
  3. Input statement problem
    By une in forum C Programming
    Replies: 3
    Last Post: 05-29-2007, 11:16 PM
  4. Prevent user input
    By bonne_tim in forum C Programming
    Replies: 11
    Last Post: 01-01-2007, 03:18 PM
  5. ~ User Input script help~
    By indy in forum C Programming
    Replies: 4
    Last Post: 12-02-2003, 06:01 AM