Problem using sscanf fgets and overflow checking

This is a discussion on Problem using sscanf fgets and overflow checking within the C Programming forums, part of the General Programming Boards category; Hi, I have trouble using sscanf and fgets to check for overflow. I will post the assignment specification so I ...

  1. #1
    Registered User
    Join Date
    Feb 2008
    Posts
    6

    Problem using sscanf fgets and overflow checking

    Hi,
    I have trouble using sscanf and fgets to check for overflow.
    I will post the assignment specification so I could help whoever would kindly like to offer his/her help.

    __________________________________________________
    1) The program should expect 2 decimal integers per line. Let's call these n1 and n2.
    2) For each such input line it should output the value of n1 + 2 * n2 (followed by a newline character '\n').
    3) If there are not 2 integers on the line or there is something other than exactly 2 integers other than whitespace, the corresponding output should be the line "illegal input".

    4) If the input is legal but the entered n1 or n2 or the calculated output value would be greater than the maximum long int value, then the corresponding output should be "overflow".
    5) If it would be less than the minimum (i.e. most negative) long int value, then the corresponding output should be "underflow".

    You can assume that the input line does not contain the null char '\0';
    You can also assume that no legal input line is longer than 50 characters (not counting the '\n' character). If such a line is encountered, the output should be "illegal input".

    RESTRICTION: n1 and n2 should be declared to be "long int". Do not try to use a "larger type" to detect overflow/underflow. Instead, use the return values, etc. to detect overflow/underflow.

    You are expected to use appropriate functions in your assignments. For example, reading the input one character at a time here is not appropriate.
    __________________________________________________

    Now to my question. I have trouble checking if the input line is longer than 50 characters using fgets and sscanf.
    Same with overflow. How do I check if n1 or n2 is overflow/underflow? As for the calculated result I think I could manage that.
    I guess I would check if n1 > LONG_MAX - n2.

    I think I will be able to do the program by reading character by character but the point of this assignment is to use tools such as sscanf fgets strlen and so on...

    I have this assignment due in 2 days and I will appreciate any comments, hints, help before then?

    Thank you very much and I will wait for your replies.

  2. #2
    uint64_t...think positive xuftugulus's Avatar
    Join Date
    Feb 2008
    Location
    Pacem
    Posts
    355
    It seems the matter is a bit more complex. Even i was surprised as it had never occurred to me a need to check for arithmetic overflows. I found the following very informative, although a bit advanced page.
    http://www.fefe.de/intof.html
    I think you need the simple solutions at the start...
    Code:
    ...
        goto johny_walker_red_label;
    johny_walker_blue_label: exit(-149$);
    johny_walker_red_label : exit( -22$);
    A typical example of ...cheap programming practices.

  3. #3
    CSharpener vart's Avatar
    Join Date
    Oct 2006
    Location
    Rishon LeZion, Israel
    Posts
    6,484
    1. if input line is longer than the buffer provided - fgets will not store \n character - so just check its present in the resulting buffer
    2. to check that n1 and n2 are out of range - scan them with sscanf, check the return value to be sure that both values are parsed, check the position with %n to see that the parsing stopped at \n character, then sprintf them back to the temp buffer and compare the 2 buffers to see that numbers are parsed ok
    3. do not forget - you need 2*n2
    The first 90% of a project takes 90% of the time,
    the last 10% takes the other 90% of the time.

  4. #4
    Registered User
    Join Date
    Feb 2008
    Posts
    6
    To xuftugulus:
    True this advanced but very useful, thank you. I even bookmarked the page
    But unfortunately it doesn't help my question.

    To vart
    Thank you very much for your reply.

    1. if input line is longer than the buffer provided - fgets will not store \n character - so just check its present in the resulting buffer
    I figured that out just before I read your comment and was very glad you confirmed it and I added an extra step to check that there is nothing other than two integers. I posted the code I wrote so far below (commented) so whoever have a similar question can benefit from it and I will be glad if you can skim through it.

    3. do not forget - you need 2*n2
    Thank you

    2. to check that n1 and n2 are out of range - scan them with sscanf, check the return value to be sure that both values are parsed, check the position with %n to see that the parsing stopped at \n character, then sprintf them back to the temp buffer and compare the 2 buffers to see that numbers are parsed ok
    Unfortunately, I still can't check n1 and n2 for over/underflow. I understood the idea that I have to reconstruct the input into a string using the variables "n1" and "n2" right after executing sscanf and then use strcmp on the two strings.
    So it would be something like this
    sprintf(tempstr, "%ld %ld", n1, n2);
    Now the problems I faced with this method is how to reconstruct the string to be exactly the same? For instance how to I deal with white space? I might be able to trim the two strings from all white spaces before comparison but even then how do I deal with inputs like?
    > 00000001111 00003
    or this
    > +123 --3
    n1 and n2 wouldn't obviously have all the zeros neither the positive and double negation signs stored in.

    While reading the man page of sprintf I saw this modifier you talked about %n and though it would be useful. I still don't know how to use it though (even after an extensive google search)?
    I get a Bus Error with
    sprintf(tempstr, "%ld %ld %n", n1, n2, %n3); /*n3 is an int*/


    As promised here is my code below:

    Code:
    #include <stdio.h>
    #include <limits.h>
    #include <inttypes.h>
    #include <string.h>
    
    
    #define MAX 50 /* MAX is 50 since I can assume that no legal input is more than 50 chars  excluding the \n */
    
    long n1, n2;
    int c;
    char str[MAX+2];
    /*  This is the string where I will store the input. 
    I added 2 to MAX to leave room for the new line character as well as for the (null) character
    which is added automatically after fgets execution. */
    
    int main(void)
    {	
    	if (fgets(str, MAX + 2, stdin) == str) /* To check if fgets ran..successfully..*/
    	{
    		if (str[strlen(str)-1] == '\n')
    /* I subtracted 1 from strlen to get to the character before the null which should be \n */
    		{
    			if (sscanf(str, "%ld %ld %1s", &n1, &n2, %c) == 2)
    			{
    				if(c == '\0')
    				{
    					if n1 and n2 is not over/underflow /* I am stuck with this part */
    					{
    						if (n1 > LONG_MAX - (2*n2))
    							printf("overflow\n");
    						if (n1 < LONG_MIN - (2*n2))
    							printf("underflow\n");
    						else
    							printf("%d\n", n1 + (2*n2));
    					}
    				}
    				else
    				{
    					printf("illegal input\n");
    				}
    			}
    			else
    			{
    				printf("illegal input\n");
    			}
    		}
    		else
    		{
    			printf("illegal input\n");
    		}
    	}
    	if (fgets(str, MAX + 2, stdin) == '\0') 
    /* This means that we have reached EOF so we need to check for illegal input of more than 50 char differently
     becuase there might not be a \n */
     	{
     		if(strlen(str) <= MAX)
     		{
     			/* I will call a function with the above code which starts with if n1 and n2 ... */
     		}
    		else
    		{
    			printf("illegal input\n");
    		}
     	}
     	else
     	{
    		printf("illegal input\n");
     	}
     	return 0;
    }
    Last edited by jou00jou; 02-18-2008 at 05:48 AM.

  5. #5
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    One option would be to NOT use sscanf(), but rather parse the string yourself, and use strtol() - as this allows for overflow checking (it clamps the number to the range MIN_LONG..MAX_LONG, and sets errno to "ERANGE" [I think]) - it also gives you a pointer back to the character where it stopped parsing, which you can check if it's at the end of the string or not [e.g. on a space, '\n' or '\0' character, depending on the circumstance) - you could also use the "parsed to" pointer to find the next string to parse, as strtol() will allow whitespace at the beginning of the string.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  6. #6
    CSharpener vart's Avatar
    Join Date
    Oct 2006
    Location
    Rishon LeZion, Israel
    Posts
    6,484
    &#37;n is for scanf not sprintf

    Code:
    {
    	long n1,n2;
    	int position;
    	char buffer[] = "1234567890123 5678\n";
    	int ret = sscanf(buffer, "%ld %ld%n", &n1,&n2,&position);
    
    	size_t bufLen = strlen(buffer);
    
    	if(ret != 2 || buffer[position] != '\n' || bufLen != (size_t)position+1)
    	{
    		/*incorrect input */
    		return -1;
    	}
    	else
    	{
    		char temp[52];
    		sprintf(temp, "%ld %ld\n", n1,n2);
    
    		if(strcmp(buffer,temp))
    		{
    			/* wrong parse */
    			return -2;
    		}
    
    	}
    	return 0;
    }
    The first 90% of a project takes 90% of the time,
    the last 10% takes the other 90% of the time.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. large program code ,please help
    By Ash1981 in forum C Programming
    Replies: 14
    Last Post: 01-30-2006, 06:16 AM
  2. popen and fgets problem
    By dkt in forum C Programming
    Replies: 1
    Last Post: 10-08-2001, 12:33 PM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21