Thread: fgets and sscanf (invented also fgetlong, seems it exists too)

  1. #1
    Registered User
    Join Date
    Sep 2013
    Posts
    6

    fgets and sscanf (invented also fgetlong, seems it exists too)

    Hello

    I cant get the use of fgets and sscanf when it comes to fetching an integer. It works well with a string. I could typecast it but I am not coming on either. Or what is the safe way of fetching integer input? I dont want scanf, it aint safe. I just imagined something like fgetint or fgetlong should exist, and it seems it does, because I put it and the compiler didn't complain.

    Well this is a very simple code. 2 structures, one inside the other. It is about storing the name, the telephone and the birthdate of a user. The birthdate is broken into day, month and year, so it makes part of a separate structure. Then, i get the name of this separate structure and put it inside the other one, just as as any other member.

    well her is the code, but I get lots of problems when trying to read that, starting with sscanf after the fgetlong. It says passing of argument 1, and 2 and 3 of strtol makes pointer from integer without a cast.

    Code:
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    
    typedef struct birthdate{
            int day;
            int month;
            int year;
            }birthdate_t;
    
    typedef struct contacto {
            char name[30];
            long telephone;
            birthdate_t bd;  // es decir, bd es de tipo struct
            } contacto_t;
    
    contacto_t create_contact(void);
    
            contacto_t create_contact(){ // it returns a structure type
            contacto_t c1; // creates actually a blank structure y and here below I just input the data for storage
    
            printf("Enter name: ");
    
            fgets(c1.name, sizeof(c1.name), stdin);
            sscanf(c1.name, "%s", &c1.name);
    
            printf("Enter telephone: ");
            fgetlong(c1.telephone, sizeof(c1.telephone), stdin);
    
            sscanf(strtol(c1.telephone, "%d", &c1.telephone));
    
            printf("Enter birthdate");
            c1.bd = create_birthdate();
        }
    
    
    birthdate_t create_birthdate(){
        birthdate_t bd1;
        Printf("Enter day: ");
        fgets(bd1.day, sizeof(bd1.day), stdin);
        sscanf(bd1.day, "%d\n", &bd1.day);
    
        Printf("Enter month: ");
        fgets(bd1.month, sizeof(bd1.month), stdin);
        sscanf(bd1.month, "%d\n", &bd1.month);
        Printf("Enter year: ");
    
        fgets(bd1.year, sizeof(bd1.year), stdin);
        sscanf(bd1.year, "%d\n", &bd1.year);
        return bd1;
    }
    
    main (void)
    {
        create_contact();
    
    }
    Last edited by Carlostudiante; 09-02-2013 at 01:24 PM.

  2. #2
    Hurry Slowly vart's Avatar
    Join Date
    Oct 2006
    Location
    Rishon LeZion, Israel
    Posts
    6,788
    if you are using strtol you do not need scanf

    strtol does not use scanf format strings - you need to read again the function description to understand its parameters.

    if you want to read long using scanf it would be

    Code:
    sscanf(buf, "%ld", &longValue);
    for strtol it would be

    Code:
    longValue = strtol(buf,NULL,0);
    Do not mix two approaches in the same sentence
    All problems in computer science can be solved by another level of indirection,
    except for the problem of too many layers of indirection.
    – David J. Wheeler

  3. #3
    Registered User
    Join Date
    Sep 2013
    Posts
    6
    Thank you. But I was told that first one has to read the input so in a sort of buffer using fgets and then the function sscanf scans that buffer. This is for security reasons to avoid the bufferoverflow for scanf. So this worked right to read in the name, being a string.

    Then for the telephone, that is where I have the problem. You mean, I don't need fgetlong to read the int? Isn't sscanf vulnerable to bufferoverflow? shouldn't I first get the input into a sort of fgets (and typecast it) or fgetint or fgetlong and then carry on with sscanf?

    I used this: sscanf(c1.telephone, "%d", &c1.telephone); and I get: the passing of argument one of sscanf makes pointer from integer without a cast

    ===================


    Quote Originally Posted by vart View Post
    if you are using strtol you do not need scanf

    strtol does not use scanf format strings - you need to read again the function description to understand its parameters.

    if you want to read long using scanf it would be

    Code:
    sscanf(buf, "%ld", &longValue);
    for strtol it would be

    Code:
    longValue = strtol(buf,NULL,0);
    Do not mix two approaches in the same sentence
    Last edited by Carlostudiante; 09-02-2013 at 01:53 PM.

  4. #4
    Registered User
    Join Date
    Sep 2013
    Posts
    6
    The compiler complains with passing argument 1 of sscanf makes pointer from integer without a cast
    Code:
    printf("Enter telephone: ");
            fgetlong(c1.telephone, sizeof(c1.telephone), stdin);
            sscanf(c1.telephone, "%ld", &c1.telephone);

  5. #5
    Registered User MutantJohn's Avatar
    Join Date
    Feb 2013
    Posts
    2,665
    Do you need parentheses around your arguments?

  6. #6
    Registered User
    Join Date
    Sep 2013
    Posts
    6
    I have read the whole Internet, and I have come to the conclusion that there is a conspiracy to not disclose how in the f**** hell can integers be read in a safe way.
    scanf is not valid because it is not safe, neither is sscanf.
    Then it has to be fgets. But fgets works fine only for strings, gets mixed up with integers. And then the most I have gotten to see is that that a typecast could be used, but they bloody never show how.

  7. #7
    - - - - - - - - oogabooga's Avatar
    Join Date
    Jan 2008
    Posts
    2,808
    Do it something like this:
    Code:
    char line[256];
    
    
    printf("Enter telephone: ");
    fgets(line, sizeof line, stdin);
    if (sscanf(line, "%ld", &c1.telephone) != 1)
    {
        /* error in input */
    }
    The cost of software maintenance increases with the square of the programmer's creativity. - Robert D. Bliss

  8. #8
    Registered User
    Join Date
    Sep 2013
    Posts
    6
    Hmm interesting, the compiler did not complain. Then my question is, looking up the code, you create a variable named "line" which will store the value I suppose. But then, what happens to the member field of my structure which is c1.telephone (being that a sort of qualified name made up of the struct name, c1, and the member itself, telephone) ?

    or is it that I am not understanding how that syntax works? so you created a variable line, sort like a temporary variable? but then actually and finally the value is stored in c1.telephone through the &c1.telephone?

    why didn't the compiler report any issue when reading the string "name" and only got confused when it came across the integer values? your code works, but the code I had for name compared to yours had to be incorrect because I am not creating any temporary variable, I just did, as you can see:

    Code:
    fgets(c1.name, sizeof(c1.name), stdin);       
    
    sscanf(c1.name, "%s", &c1.name);
    Last edited by Carlostudiante; 09-02-2013 at 03:27 PM.

  9. #9
    - - - - - - - - oogabooga's Avatar
    Join Date
    Jan 2008
    Posts
    2,808
    fgets read a line of input from the given stream (e.g., stdin) and puts it into the given string variable (i.e., an array of chars).

    So if you're just reading a string from a single line, there's nothing left to do after the fgets. The fgets in your previous post puts the line read (including the newline character) into the given string variable.

    But if you want a true numeric value (as opposed to a string holding the characters making up the display version of the value) then you first read it as a string and then "scan" the string to convert the characters into a true number. (It's a good exercise to consider how you would write a function to do that.)

    And it never makes sense to put the same variable name in the first and last positions of sscanf.

    If you need to remove the newline from the string read with fgets (for instance, after you've read c1.name) then you have to do something like this:
    Code:
    size_t len = strlen(c1.name);
    
    if (c1.name[len-1] == '\n')
        c1.name[len-1] = '\0';
    The cost of software maintenance increases with the square of the programmer's creativity. - Robert D. Bliss

  10. #10
    Registered User
    Join Date
    Sep 2013
    Posts
    6
    Alright!, thank you very much. I appreciate the time you took, I spent two days with this issue and it was very confusing despite having read countless samples of fgets but nowhere it was explained like that.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Help with reading a file in C, with fgets()/sscanf()
    By ErickN in forum C Programming
    Replies: 3
    Last Post: 04-23-2011, 10:54 AM
  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 question.....
    By Ash1981 in forum C Programming
    Replies: 12
    Last Post: 01-06-2006, 01:31 PM
  4. Fgets + sscanf
    By MethodMan in forum C Programming
    Replies: 3
    Last Post: 03-15-2004, 08:53 PM
  5. fgets && sscanf
    By GaPe in forum C Programming
    Replies: 3
    Last Post: 12-24-2001, 05:39 PM

Tags for this Thread