Thread: Validation design

  1. #1
    Registered User
    Join Date
    Jun 2012
    Posts
    127

    Validation design

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    
    int main()
    {
    	int stop, ch, valid = 0;
    
    
    	do
    	{
    		// display title
    		printf("Individual Salesman Commission\n");
    		printf("==============================\n");
    
    
            // prompt and read salesman id
            printf("Salesman ID (NO.): ");
            scanf("%d", &stop);
    
    
    		// Only give user to pass if it is number
    		while ( (ch = getchar()) != '\n')
    		{
    			// if it is not valid input
    			if(ch > 1)
    			{
    				while ( (ch = getchar()) != '\n');
    
    
    				printf("Invalid input. Please input again...\n");
    				getchar();
    				system("cls");
    
    
    				// display title
    				printf("Individual Salesman Commission\n");
    				printf("==============================\n");
    
    
    				// prompt and read salesman id
    				printf("Salesman ID (NO.): ");
    				scanf("%d", &stop);
    			} // end if
    		} // end while
    
    
            valid = 1; // end loop process
    		
    		// clear screen display  
    		system("cls");
    	} while (valid == 0); // loop if the input is invalid
    
    
    	if(stop <= 0 )
    	{
    		// Display error message
    		printf("No record found.\n");
    	} // end else
    
    
    	printf("Press Enter to exit program...\n");
    	getchar();
    
    
    } // end function main
    I can't understand why input '-' or '+' jump to display no record found.

  2. #2
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Don't post again until you have read and fully understood this link.

    You are assuming that people will understand what problem you're having, despite giving minimal (and, as it happens, useless) relevant information.
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

  3. #3
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    You should initialise 'stop' and check the return value of scanf. Perhaps that will solve your issue.
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  4. #4
    Registered User
    Join Date
    Jun 2012
    Posts
    127
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    
    int main()
    {
    	int stop, ch, valid = 0;
    
    
    	do
    	{
    		// display title
    		printf("Individual Salesman Commission\n");
    		printf("==============================\n");
    
    
            // prompt and read salesman id
            printf("Salesman ID (NO.): ");
            scanf("%d", &stop);
    
    
    		// Only give user to pass if it is number
    		while ( (ch = getchar()) != '\n'|| stop < 1)
    		{
    			// if it is not valid input
    			if(ch > 1)
    			{
    				while ( (ch = getchar()) != '\n');
    
    
    				printf("Invalid input. Please input again...\n");
    				getchar();
    				system("cls");
    
    
    				// display title
    				printf("Individual Salesman Commission\n");
    				printf("==============================\n");
    
    
    				// prompt and read salesman id
    				printf("Salesman ID (NO.): ");
    				scanf("%d", &stop);
    			} // end if
    		} // end while
    
    
            valid = 1; // end loop process
    		
    		// clear screen display  
    		system("cls");
    	} while (valid == 0); // loop if the input is invalid
    
    
    	if(stop <= 0)
    	{
    		// Display error message
    		printf("No record found.\n");
    	} // end else
    
    
    	printf("Press Enter to exit program...\n");
    	getchar();
    
    
    } // end function main

    There is a issue that after I input '-' or '+' symbol, you enter to enter 2 times to continue when reaching "Invalid input. Please input again..." statement. It is due to the scanf("%d", &stop) grabs '-' or '+' symbol and then the newline grabs the newline. You can test with the following code:

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    
    int main()
    {
    	int stop, ch, valid = 0;
    
    
    	do
    	{
    		// display title
    		printf("Individual Salesman Commission\n");
    		printf("==============================\n");
    
    
            // prompt and read salesman id
            printf("Salesman ID (NO.): ");
            scanf("%d", &stop);
    
    
    		printf("value: %d\n",stop);
    		system("pause");
    		// Only give user to pass if it is number
    		while ( (ch = getchar()) != '\n'|| stop < 1)
    		{
    			printf("ch: %d\n",ch);
    			system("pause");
    			// if it is not valid input
    			if(ch > 1)
    			{
    				while ( (ch = getchar()) != '\n');
    
    
    				printf("Invalid input. Please input again...\n");
    				getchar();
    				system("cls");
    
    
    				// display title
    				printf("Individual Salesman Commission\n");
    				printf("==============================\n");
    
    
    				// prompt and read salesman id
    				printf("Salesman ID (NO.): ");
    				scanf("%d", &stop);
    			} // end if
    		} // end while
    
    
            valid = 1; // end loop process
    		
    		// clear screen display  
    		system("cls");
    	} while (valid == 0); // loop if the input is invalid
    
    
    	if(stop <= 0)
    	{
    		// Display error message
    		printf("No record found.\n");
    	} // end else
    
    
    	printf("Press Enter to exit program...\n");
    	getchar();
    
    
    } // end function main
    So, how should I modify the code to solve this issue?

  5. #5
    Registered User
    Join Date
    May 2012
    Posts
    1,066
    Have you ever heard of the KISS principle?

    A simple do-while-loop is all you need:
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    int main()
    {
        int nr = 0, ch;
    
        do
        {
            printf("Enter number: ");
            scanf("%d", &nr);
            while ((ch = getchar()) != '\n' && ch != EOF)
                ;
            if (nr < 1)
                puts("\nInvalid number, try again");
        } while (nr < 1);
        
        return 0;
    }
    Whenever you want to flush the input stream after a scanf()-call do it immediately.

    Bye, Andreas

  6. #6
    Registered User
    Join Date
    Jun 2012
    Posts
    82
    But Andi, that doesn't really work when you enter something like 1a, 1- or 2abcd.. ( basically any numbers followed by a character or string)

    And when user input ' - ', it goes straight into getchar()? If true, is it because of scanf() itself only reads the format specified by the coder, other than that it will be discarded? Well this is what I thought of after setting up breakpoints and monitor the values in each variable.

    If I'm wrong, hope you can explain it step by step. Thanks!

    Oh and I modified your code to be able to fix the problem I mentioned. Is this okay?
    *ps : it doesn't work after I enter 111ddd , and +
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    
    int main()
    {
        int nr = 0, ch;
    
    
        printf("Enter number: ");
        do
        {
            scanf("%d", &nr);
            while ( (ch = getchar()) != '\n' && ch != EOF){
                if(ch > 1){
                    printf("\nError : ");
                    while ( (ch = getchar()) != '\n' && ch != EOF);
                    scanf("%d",&nr);
                }
            }
            if(nr < 1){
                printf("\nError : ");
            }
        } while (nr < 1);
    
    
        return 0;
    }
    Last edited by xeon321; 11-19-2012 at 06:21 AM.

  7. #7
    Registered User
    Join Date
    May 2012
    Posts
    1,066
    Quote Originally Posted by xeon321 View Post
    But Andi, that doesn't really work when you enter something like 1a, 1- or 2abcd.. ( basically any numbers followed by a character or string)
    My code is tolerant and accepts a number if the input starts with it and discards any following characters.
    If you only want "clean" numbers (nothing before and after) I suggest a combination of fgets() and sscanf() because mixing scanf() and getchar() is always tricky.
    Code:
    #include <stdio.h>
    #include <errno.h>
    #include <string.h>
     
    int main(void)
    {
        int nr, items;
        char ch;
     
        while (1)
        {
            char buf[20];
    
            printf("Enter number: ");
            fgets(buf, sizeof(buf), stdin);
    
            errno = 0;
            items = sscanf(buf, "%d%c", &nr, &ch);
            if (items == 2 && ch == '\n')
                if (errno == ERANGE)
                    puts("Number out of range, try again");
                else if (nr > 0)
                    break;
                else
                    puts("Number must be greater 0, try again");
            else
                puts("Not a number, try again");
    
            if (buf[strlen(buf) - 1] != '\n')
                while ((ch = getchar()) != '\n' && ch != EOF)
                    ;
        }
        printf("The number is %d\n", nr);
         
        return 0;
    }
    On line 10 we start an infinite loop.
    On line 15 we read the input into our buffer.
    On line 17 we set "errno" to 0 so that we can be sure that any error we get is from sscanf() on the following line.
    On line 18 we try to extract a number from the input and the character following the number. We also store the return value from sscanf().
    On line 19 we check if we've got two items from sscanf() (the number and the following character) and if the character is the newline (thus there was nothing after the number).
    If both conditions are true we check if the number is a valid integer. If the number is out of range (either smaller than INT_MIN or bigger than INT_MAX) than "errno" will be set to ERANGE (a macro defined in <errno.h>).
    Then we check for an optional valid range for our program (in this case we only want positive numbers starting with 1). If the number is ok we break out of the loop else we print an error message.
    If the condition on line 19 wasn't true, we didn't get a number from the user and print an error message.

    Finally we check on line 29 if fgets() has read the newline character (the user has inputted less characters than our buffer is able to hold). If the last character in the input isn't the newline, there are still characters left in the input stream which we will consume. Thus we will start again with an empty input stream.

    Bye, Andreas

  8. #8
    Registered User
    Join Date
    Jun 2012
    Posts
    127
    Validation design-c-jpg

    bug.

  9. #9
    Registered User
    Join Date
    Jun 2012
    Posts
    82
    Quote Originally Posted by grumpy View Post
    Right 98% of the time, and don't care about the other 3%.
    There you go

  10. #10
    Registered User
    Join Date
    May 2012
    Location
    Arizona, USA
    Posts
    945
    ulti-killer: AndiPersti's code works fine for me for the same input (eleven 9's). Can you post your current code?

  11. #11
    Registered User
    Join Date
    Jun 2012
    Posts
    127
    I just compile the code of AndiPersti

  12. #12
    Registered User
    Join Date
    Sep 2001
    Posts
    4,912
    The '1215752191' is because you're in a 32-bit architecture (and it worked for christop because he's probably on a 64-bit architecture). Eleven 9's is too big to be represented in a 32-bit integer, so it wraps around. If you look at only the least significant 32-bits, the number '99999999999' is actually '1215752191'. When you hit 2^32 your arithmetic wraps around and starts from zeros (when you're using signed numbers, it will wrap around into negative numbers because of two's complement).

    If you want to work with numbers that are arbitrarily large, the GMP library does exactly that (and will use function calls to do each operation and break it down into steps that will fit on your processor). For most purposes, the int type is sufficient.

  13. #13
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    On line 19 we check if we've got two items from sscanf() (the number and the following character) and if the character is the newline (thus there was nothing after the number).
    If both conditions are true we check if the number is a valid integer. If the number is out of range (either smaller than INT_MIN or bigger than INT_MAX) than "errno" will be set to ERANGE (a macro defined in <errno.h>).
    Then we check for an optional valid range for our program (in this case we only want positive numbers starting with 1). If the number is ok we break out of the loop else we print an error message.
    Well the problem here is that sscanf does NOT set errno on any kind of numeric overflow.
    It just keeps accumulating digits (and silently overflowing) until there are no more digits.

    If you want ERANGE type detection, use strtol() or strtoul() (or strtod for floats/doubles)
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  14. #14
    Registered User
    Join Date
    May 2012
    Posts
    1,066
    Quote Originally Posted by Salem View Post
    Well the problem here is that sscanf does NOT set errno on any kind of numeric overflow.
    It just keeps accumulating digits (and silently overflowing) until there are no more digits.
    You're right. I haven't read the man-page carefully enough:
    CONFORMING TO
    The functions fscanf(), scanf(), and sscanf() conform to C89 and C99 and POSIX.1-2001. These standards do not specify the ERANGE error.
    So ERANGE for sscanf() only works with the GNU C Library.

    Bye, Andreas

  15. #15
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    Heh, and I hadn't realised that gcc had this sneaky addition over the standard.
    Code:
    #include <stdio.h>
    #include <errno.h>
    #include <string.h>
    #include <limits.h>
     
    int main(void)
    {
        int nr, items;
        char ch;
        printf("%d\n",INT_MAX);
        printf("%lld\n",LLONG_MAX);
     
        while (1)
        {
            char buf[30];
    
            printf("Enter number: ");
            fgets(buf, sizeof(buf), stdin);
    
            errno = 0;
            items = sscanf(buf, "%d%c", &nr, &ch);
            if (items == 2 && ch == '\n')
                if (errno != 0)
                    perror("Number out of range, try again");
                else
                    break;
            else
                puts("Not a number, try again");
    
            if (buf[strlen(buf) - 1] != '\n')
                while ((ch = getchar()) != '\n' && ch != EOF)
                    ;
        }
        printf("The number is %d\n", nr);
         
        return 0;
    }
    However, it seems to be almost completely useless.
    Code:
    $ ./a.out 
    2147483647
    9223372036854775807
    Enter number: 2147483648
    The number is -2147483648
    
    $ ./a.out 
    2147483647
    9223372036854775807
    Enter number: 9223372036854775808
    Number out of range, try again: Numerical result out of range
    Enter number: 9223372036854775807
    The number is -1
    It only seems to generate ERANGE if the number input exceeds the limits of long long int, regardless of the width of the datatype being converted at the moment.

    If you have to read your data into the longest data type, then manually check the range to see if will fit in a smaller int, then you may as well use strtol() from the outset. It's the same PITA either way.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Validation
    By ulti-killer in forum C Programming
    Replies: 5
    Last Post: 11-15-2012, 01:16 PM
  2. validation in c
    By thangarasu1988 in forum C Programming
    Replies: 4
    Last Post: 01-05-2012, 02:42 PM
  3. validation
    By Ideswa in forum C++ Programming
    Replies: 11
    Last Post: 01-30-2006, 01:01 PM
  4. need help in validation
    By dholman in forum C Programming
    Replies: 2
    Last Post: 01-08-2004, 09:27 AM
  5. Help with validation
    By boontune in forum C++ Programming
    Replies: 8
    Last Post: 01-10-2003, 09:44 AM