Thread: Problem with stdin, fgets, and sscanf

  1. #1
    Registered User
    Join Date
    May 2014
    Posts
    3

    Problem with stdin, fgets, and sscanf

    Hi All,

    This is my first post, and I'm new to C/C++. I am attemping to use fgets and sscanf to read a line of input, and confirm it is a positive number.

    My code works great, except for the case of a negative number. When I enter a negative number, my while loop seems to run infinitely, with stdin providng the same input over and over again. I can't figure this out for the life of me, so any help is really appreciated.

    Here's the code snippet:
    Code:
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    
    #define TEXT_LEN 64
    
    void foo() {
      char* inStr = (char*)malloc(sizeof(char)*TEXT_LEN);
      memset(inStr, 0, TEXT_LEN);
    
      printf("Enter in a positive integer.\n");
      while(fgets(inStr, 63, stdin)) {
        if (sscanf(inStr, "%d") != 1) {
          printf("Invalid integer. Try again\n");
        } else {
          int inInt = strtol( inStr, NULL, 10 );
          if ( inInt < 0 ) {
            printf("That integer isn't positive.\n");
          }
        }
      }
    
      free(inStr);
    }
    
    int main() {
      foo();
      printf("OUT\n");
    
      return(EXIT_SUCCESS);
    }

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,323
    You should not be using sscanf since you are using strtol. If you do want to use sscanf, then you should provide another argument to sscanf in order to store the result of the parsng.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    38,658
    > if (sscanf(inStr, "%d")
    Well this is going to spray the result of the conversion over some unknown location.
    You missed supplying a parameter, so the whole thing is broken.

    Besides, you can do the whole thing (and much better) by just calling strtol() to being with.
    strtol(3): convert string to long integer - Linux man page

    Roughly
    Code:
    char *end;
    int inInt = strtol( inStr, &end, 10 );
    if ( errno == 0 && end != inStr ) {
      // success
    } else {
      // check the manual page for the various error codes.
      // also, check for end == inStr, when there is nothing to convert.
    }
    > while(fgets(inStr, 63, stdin))
    Replace 63 with TEXT_LEN
    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.

  4. #4
    Registered User
    Join Date
    Jun 2011
    Posts
    4,508
    > while(fgets(inStr, 63, stdin))
    Replace 63 with TEXT_LEN
    @OP: Just to give a little more information on this:

    char * fgets ( char * str, int num, FILE * stream );

    Reads characters from stream and stores them as a C string into str until (num-1) characters have been read or either a newline or the end-of-file is reached, whichever happens first.
    The second argument to "fgets()" already "takes one off" the size you give it, so you don't have to manually provide one less than the size of your array.

  5. #5
    Registered User
    Join Date
    May 2014
    Posts
    3

    Fixed

    Quote Originally Posted by laserlight View Post
    You should not be using sscanf since you are using strtol. If you do want to use sscanf, then you should provide another argument to sscanf in order to store the result of the parsng.
    Thanks a lot guys. It works now! I decided to pass the reference to inInt into sscanf.

    Code:
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    
    #define TEXT_LEN 64
    
    void foo() {
      char* inStr = (char*)malloc(sizeof(char)*TEXT_LEN);
      memset(inStr, 0, TEXT_LEN);
      int inInt;
    
      printf("Enter in a positive integer.\n");
      while(fgets(inStr, TEXT_LEN, stdin)) {
        if (sscanf(inStr, "%d", &inInt) != 1) {
          printf("Invalid integer. Try again\n");
        } else {
          if ( inInt < 0 ) {
            printf("That integer isn't positive.\n");
          } else {
            break;
          }
        }
      }
    
      free(inStr);
    }
    
    int main() {
      foo();
      printf("OUT\n");
    
      return(EXIT_SUCCESS);
    }

  6. #6
    Registered User
    Join Date
    Jun 2011
    Posts
    4,508
    FYI: You don't need to cast "malloc()": FAQ > Casting malloc - Cprogramming.com

  7. #7
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,323
    Well, in this case you probably don't even need malloc.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  8. #8
    Registered User
    Join Date
    May 2014
    Posts
    3
    Quote Originally Posted by laserlight View Post
    Well, in this case you probably don't even need malloc.
    Yes, malloc is not needed. I was just playing

  9. #9
    Registered User
    Join Date
    Jun 2009
    Posts
    120
    Quote Originally Posted by cronuscronus View Post
    Code:
    if ( inInt < 0 ) {
      printf("That integer isn't positive.\n");
    }
    That conditional is not quite right as 0 is neither positive nor negative.

  10. #10
    Registered User
    Join Date
    May 2009
    Posts
    4,035
    Quote Originally Posted by DRK View Post
    That conditional is not quite right as 0 is neither positive nor negative.
    Why worry about that; since the value of inInt is random junk (undefined).

    Tim S.
    "...a computer is a stupid machine with the ability to do incredibly smart things, while computer programmers are smart people with the ability to do incredibly stupid things. They are,in short, a perfect match.." Bill Bryson

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. fgets() from stdin and strcat()
    By rocketman03 in forum C Programming
    Replies: 9
    Last Post: 11-01-2008, 01:31 PM
  2. Problem using sscanf fgets and overflow checking
    By jou00jou in forum C Programming
    Replies: 5
    Last Post: 02-18-2008, 06:42 AM
  3. Fgets + sscanf
    By MethodMan in forum C Programming
    Replies: 3
    Last Post: 03-15-2004, 08:53 PM
  4. using stdin in fgets
    By Unregistered in forum C Programming
    Replies: 2
    Last Post: 04-14-2002, 09:14 PM
  5. fgets && sscanf
    By GaPe in forum C Programming
    Replies: 3
    Last Post: 12-24-2001, 05:39 PM