Thread: Number user input

  1. #31
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    Quote Originally Posted by Bayint Naung View Post
    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!
    So just make a conditional return, at the end of the function. Either <min or >max could be a normal unrecoverable error. It just so happens the only unrecoverable errors are:
    Code:
        if (ferror (stdin) || feof (stdin)) {
            clearerr (stdin);
            return min - 1;
        }
        else {
            return return_value;
        }
    I would stick to comparing errno with 0 or errno.h macros. errno is a standardized variable, so use your own flags rather than extending errno.

  2. #32
    Registered User jimtuv's Avatar
    Join Date
    May 2010
    Location
    Sylvania, Ohio
    Posts
    94
    Quote Originally Posted by whiteflags View Post
    So just make a conditional return, at the end of the function. Either <min or >max could be a normal unrecoverable error. It just so happens the only unrecoverable errors are:
    Code:
        if (ferror (stdin) || feof (stdin)) {
            clearerr (stdin);
            return min - 1;
        }
        else {
            return return_value;
        }
    I would stick to comparing errno with 0 or errno.h macros. errno is a standardized variable, so use your own flags rather than extending errno.
    This brings up another point I am wrestling with. Is is better to do all the error checking inside the function and force reentry from there or is it better to do that outside. I could pass a pointer to the function to change the value of the variable I want to contain the input number and then use the return for any error condition that occurred.

    Code:
    int main(void){
    
    	int number, min, max, errorCode;
    	
    	do{
    		UserInput(&number, min, max);
    	}
    	while (errorCode);	
    	
    }
    
    int UserInput( int *pNumb, min, max){
    	
    	int errorCode;
    	char buffer[BUFSIZ];
    	char *pEnd;
    	
    	errorCode = 0;
    	
    	// get the input with fgets 
    	*pNumb = strtol(buffer,&pEnd,10);
    	// check if valid then set errorCode 	
    	
    	
    	return errorCode;
    }
    or force the reentry inside the function.

    Code:
    int main(void){
    
    	int number, min, max	
    	
    	number = UserInput(min, max);	
    	
    }
    
    int UserInput(min, max){
    	
    	int errorCode;
    	int input
    	char buffer[BUFSIZ];
    	char *pEnd;
    	
    	errorCode = 0;
    	
    	do{	
    		// get the input with fgets 
    		input = strtol(buffer,&pEnd,10);
    		// check if valid then set errorCode 	
    	}
    	while (errorCode);
    	
    	return input;
    }
    Does it even matter?? My thought is that the force of reentry is better inside the function and returning input not errorCode.

  3. #33
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    A function should do one thing and should do it well. It is all up to the definition.
    Should the function retrieve (valid) input or just retrieve input?
    If you put all the error checking inside the function, you get less to get everywhere, leading to potentially less bugs and saved time.
    On the other hand, if you put the error checking outside the function, you get more flexibility.
    It's a trade-off.

    That said, I would put it all inside the function and change the interface as required to accommodate code in other places that require access to this error.
    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.

  4. #34
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    I don't think that is correct at all, Elysia. At least, I don't think we should be talking about "flexibility" and "saved time". Input is where we spend time, in the first place, so boo. We can be clearer than that.

    In order to do one thing and do it well, be capable of dividing what becomes complicated into subtasks. Example output:

    Please choose from 0 to 20.
    Enter number:
    fjefere;tejifej
    Please enter only your number.

    Please enter only your number.
    234jiwfojf
    Please enter only your number.
    234
    Please make your number in the range [0, 20).
    12

    and the implementation is:
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <errno.h>
    #include <string.h>
    
    long int InputNumber (long int min , long int max)
    {
        long int result = min - 1;
    
        char part[BUFSIZ];
        char *end = part;
        while (fgets (part , sizeof part , stdin) != NULL) {
            errno = 0;
            result = strtol (part , &end , 10);
            if (errno != 0) {
                perror ("Please try again");
                continue;
            }
    
            if (end == part || *end != '\n') {
                fputs ("Please enter only your number.\n" , stderr);
                continue;
            }
    
            if (result > max || result < min) {
                fprintf (stderr , "Please make your number in the range [%ld, %ld).\n" , min , max);
            }
            else {
                break;
            }
        }
    
        if (ferror (stdin) || feof (stdin)) {
            result = min - 1;
            clearerr (stdin);
        }
    
        return result;
    }
    
    int main ()
    {
        long int result = 0;
        const long int MIN = 0;
        const long int MAX = 20;
    
        printf ("Please choose from %ld to %ld.\nEnter number:\n", MIN , MAX);
        result = InputNumber (MIN , MAX);
    
        return 0;
    }
    We can see that already, something as simple as this can allow strtol to be very stringent. However that may not be enough. You may have concerns like "what if a user types more than BUFSIZ bytes" or "why is input padded with spaces valid?" Keep in mind that doing one thing well implies using an appropriate number of functions to do a big task. You can answer these questions by doing the line reading differently: perhaps with another function (or two) to alleviate these concerns.
    Last edited by whiteflags; 06-12-2010 at 10:55 AM.

  5. #35
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by whiteflags View Post
    I don't think that is correct at all, Elysia. At least, I don't think we should be talking about "flexibility" and "saved time". Input is where we spend time, in the first place, so boo. We can be clearer than that.
    What isn't right?
    As a general rule, flexibility drops if you do error handling inside your function. I just want jimtuv to consider that when creating functions.
    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.

  6. #36
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    "Flexibility" is not something that springs to mind when I consider input. Are things really more flexible? You want input to be correct. Is correct flexible because of where verification takes place? Where this verification takes place is unimportant considering how the verification is done is important. You can't just say things are flexible when you have error codes. That's meaningless. You can use error codes and ignore them.

    But a careful implementation avoids and even forgives all sorts of errors. Consider if we have
    1. a line reading function that always works
    2. a stringent string-to-number conversion function like strtol that always works
    3. and the cooperation of users, eventually

    Define always works, then input is always correct. In other words, you did one thing, and then took all those things and did something more.

  7. #37
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    But if we take the input example, we can split it into parts:
    - Read input.
    - Convert it to a proper type.
    - Verify that the input is correct (ie is a valid time?)
    If you fail at any stage, what do you do? You could output an error. But that error would be hard coded; unable to change since it's inside the function. Outside functions cannot change it. You loose flexibility.
    Now, we could modify the interface to allow us to pass along strings to print as error messages.
    But how do we do the verification? What is right? And what is wrong? There is so many types of input. And the verification is hard-coded; the outside cannot change it.
    We can modify the interface again to provide a callback function that should return true or false depending on whether it's valid.
    If it isn't valid, we could print an error. But what if we want to print a different error depending on the type of error in the verification? We could try printing out stuff inside the verification routine. But the input function would still print out the standard error string we passed to it. It's hard coded. We can't change it.

    So, as we see, the more error handling and stuff a function does, the less flexibility we have. The more we handle outside, the better flexibility, but more duplicated code. And duplicated code leads to maintenance nightmare and bugs.

    This is what I wanted jimtuv to understand and ponder when writing functions.
    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.

  8. #38
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    It's rather telling that you think something hard-coded like an error code can become flexible.

    Errors are not things you change. Errors are things from which to recover.

    Yes, if your goal is to define one input function and use it for the rest of your life, you're going to have a hell of a time because it has to be flexible. But that is not what we're doing and not what we need to consider.

    I just want jimtuv to understand functional decomposition, which is pretty fundamental, and goes beyond input. It's how I learned to program procedurally, and it's something I'm going to talk about instead of using buzzwords, and stuff. Especially when you misrepresent what functional decomposition is.

  9. #39
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by whiteflags View Post
    Errors are not things you change. Errors are things from which to recover.
    But the original question is how to handle these errors? Inside the function? Or outside the function?
    I think I've lined that up pretty well. The advantages and disadvantages.
    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.

  10. #40
    Registered User jimtuv's Avatar
    Join Date
    May 2010
    Location
    Sylvania, Ohio
    Posts
    94
    Is functional decomposition the process of understanding the whole (function) by resolving the relationships of the parts of that function?? Or am I thinking of only of the mathematical definition.

    Yes I do fully understand that an error is something that would be recovered from. I also get the point that flexability is a consideration but getting input is a matter to itself.

    Any time input is called for then danger is present no matter the form of input. It is the area that is not 100% reliable in any circumstance. That is why I am spending so much time on this one piece of code. Not that I intend to use it forever but to completely understand the ramifications of getting input and how to deal with each vulnerability.

    I quickly figured out that if I misuse a function (scanf, fgets etc...) the problems that it causes can be quite harsh. That brought me quickly to staying clear of functions that cant properly be
    used safely (gets etc..)

    I am still leaning to the side of caution. That input almost requires the use of error checking within the function not from without. I come to this conclusion thinking of maintainability. If someone else were to maintain the code it would be better for them if the error checking and recovery were done inside functions that call for input. As to avoid the possibility they would not due the proper error checking.

    Yes Elysia you have shown the advantages and disadvantages well. I appreciate both of your points of view they sure have me thinking. I know this will be the type of question I will ask myself many time in the future when I make functions that is why it is so important I understand the type of questions to ask. And the consideration that I should be examining.

  11. #41
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by jimtuv View Post
    Any time input is called for then danger is present no matter the form of input. It is the area that is not 100% reliable in any circumstance.
    This is not true. If you know 100% what is being done with the input (and therefore what vulnerabilities exist along the way) you can ensure 100% that any possible exploits in the input are neutralized.

    For example, possible exploits on an SQL database are 100% known and documented. If you know what they are, you can prevent them. This is not to say that this covers what you do with the information in the db, only that the db itself will not have problems.

    This applies to anything. If you can correctly identify possible issues, you can ensure your input is safe. That is the major point of not permitting buffer overflows: there is nothing you can put into a string that will cause a problem for a C program unless that string overflows its bounds. If that happens, malicious code can be injected into the running executable itself.
    Last edited by MK27; 06-12-2010 at 01:10 PM.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  12. #42
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    Is functional decomposition the process of understanding the whole (function) by resolving the relationships of the parts of that function?? Or am I thinking of only of the mathematical definition.
    Unfortunately, I am not very clear on the math definition, although I am aware of it. Take this with a grain of salt, but I think you have it backwards. I will elaborate to be clear as mud.

    Functional decomposition is a consideration in the planning phase and maintenance phase. To put it in context, InputNumber can certainly be written the way you consider best. You can handle errors where you want. Considering how you want it done, it will be easier to do correctly if InputNumber relies on parts that you know work correctly, or at least how you expect.

    As you're learning now, fgets is not everything you need. It results in errors you need to address. So as they say, "roll your own". Build yet another function in order to build this one. Eventually you're going to hit bedrock and everything will work just fine.

  13. #43
    Registered User jimtuv's Avatar
    Join Date
    May 2010
    Location
    Sylvania, Ohio
    Posts
    94
    so that is why gets(buffer); is so dangerous? Because unlike fgets(buffer,sizeof buffer,stdin); does not have the size of the buffer?

    Also a question I have been thinking about is. If you have insured that the buffer can't be overwritten then you wouldn't be much concerned by someone sending a huge amount of data to stdin because the OS would handle that wouldn't it? The only consideration would be to clear the junk out of stdin before getting more input correct?? How do you know if that is the case. I know if you check the stdin for data and it's empty it will just sit and wait for data before continuing. So how can you check stdin without the pause when it's empty?? Or should the question be after using fgets how does one know if extra data was input?

  14. #44
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    stdin is by default a line buffered stream. Buffered means how long you have to wait before something happens. If I type a bunch of crap, the program assumes control again after I press <enter>. In a line buffered stream, all lines end with '\n' as a signal that input is complete.

    The easiest thing to do is just take it all. If fgets returns a full buffer and you find no '\n' just store the part somewhere else and keep reading.

  15. #45
    Registered User jimtuv's Avatar
    Join Date
    May 2010
    Location
    Sylvania, Ohio
    Posts
    94
    from Wikipidia;

    functional decomposition has a prominent role in computer programming, where a major goal is to modularize processes to the greatest extent possible. For example, a library management system may be broken up into an inventory module, a patron information module, and a fee assessment module. In the early decades of computer programming, this was manifested as the "art of subroutining," as it was called by some prominent practitioners.

    I love Google search!

    To take all of what is put in stding woudn't that take a variable length array?? Or I could just save the good and just chuck the leftover would be the my first thought.

    is in better to just loop the fgets or do something like

    Code:
    while(getchar(); != '\n');
    to clear out the junk.

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