understanding sscanf() function

This is a discussion on understanding sscanf() function within the C Programming forums, part of the General Programming Boards category; Hello every one, I was looking for ways to stop using scanf() as it has got the obvious bug when ...

  1. #1
    Registered User
    Join Date
    Sep 2012
    Posts
    55

    understanding sscanf() function

    Hello every one,

    I was looking for ways to stop using scanf() as it has got the obvious bug when handling string data,
    and also sometimes it holds the inputs coming from stdin ,and i have to use fflush() to flush out the input, which again is harmful.

    Looking at a few forum threads here ,many have recommended using fgets() with sscanf(),simply put(please correct me if i am wrong) we are getting the data from the user through fgets() and extracting the data from a buffer(linked to fgets()) in a formatted way using sscanf() .

    Now looking at sscanf() example from
    sscanf - C++ Reference

    a.I am confused as to why there is a pointer "%*s" in the statement rather than just "%s" ?
    b.If, char sentence[] = "12 abc 24";
    then
    sscanf( buffer, "%d %d", &int1,int2 );
    will int1 contain 12 and int2 contain 24?

  2. #2
    Registered User
    Join Date
    Jun 2005
    Posts
    6,307
    1) Using fflush() on any input stream gives undefined behaviour, regardless of whether you are using scanf() ot fgets(). In short, don't use fflush(stdin) - ever.

    2) Yes, a common use case is to employ fgets() to read a string, and sscanf() to scan the received string. There is no linkage of any buffer to fgets() or sscanf() in doing so (at least, no more linkage than is implied by fgets() reading characters to an array, and sscanf() to interpret the data that fgets() places there).

    3) The * modifier on a format means to discard data, rather than write it to a subsequent argument. So, %*s means act as if %s was used, but discard the string rather than writing it.

    So, in that link
    Code:
    sscanf (sentence,"%s %*s %d",str,&i);
    is equivalent to
    Code:
    sscanf(sentence, %s %s %d, str, buffer_to_discard, &i);
    if we assume that buffer_to_discard is an array of char large enough to hold the results of the second %s format. The advantage of %*s is that it discards the second string, without having to mess around trying to estimate its length (or worry about chaos that might ensue from a buffer overflow if buffer_to_discard is too short).

    Note: the return value from the second sscanf() call will be different than the first, but the code you linked to is not checking the return value anyway.
    Last edited by grumpy; 01-03-2014 at 03:24 AM.
    Right 98% of the time, and don't care about the other 3%.

  3. #3
    Registered User
    Join Date
    Sep 2012
    Posts
    55
    Thanks for the quick reply Mr. grumpy.
    I see,yes the %*s is much simpler to use rather than to use another array to store the discarded data (buffer_to_discard),however sscanf() is only useful if i know the exact contents of the buffer array.In many real time situations i may not know the exact contents of that buffer array,all i do know that it will contain only one number(int) every time,but i will not know in which index position it will be stored in the array,This being the case how can i use sscanf() to extract that int from the buffer array?

  4. #4
    Registered User
    Join Date
    Jun 2005
    Posts
    6,307
    Your question is too general. Not all styles of input suited to the fgets()/scanf() sequence.

    You need to decide how you will skip over characters that do not form an integral value, and then extract the integral value. Maybe that will involve sscanf(). Maybe it won't.

    Without a concrete specification of what input you expect (and how the input might vary) it is not possible to give a solution. If you give that specification then, maybe, someone will offer a solution (which might or might not involve using sscanf()). Without that specification, you're essentially asking for a general solution where none exists.
    Right 98% of the time, and don't care about the other 3%.

  5. #5
    Registered User
    Join Date
    Nov 2012
    Posts
    1,100
    Quote Originally Posted by ak47 View Post
    however sscanf() is only useful if i know the exact contents of the buffer array.In many real time situations i may not know the exact contents of that buffer array,all i do know that it will contain only one number(int) every time
    Can you give examples of what you mean by "it will contain only one number every time". When you use fgets, you read an entire line. When you use sscanf you can get integers or whatever else from that line. It doesn't matter what the "index position" of where the integers appear on that line.

  6. #6
    Registered User
    Join Date
    Sep 2012
    Posts
    55
    Let me give you an example of the buffer array.
    Code:
    buffer_array[] = "operation1 error code NULL  \n operation2 error code 10 \n operation3 error code STOP";
    or
    buffer_array[] = "operation1 error code 8 \n operation2 error code STOP \n operation3 error code STOP";
    or 
    buffer_array[] = "operation1 error code NULL \n operation2 error code NULL \n operation3 error code 8";
    I simply cannot use
    Code:
    int a = 0;
    sscanf(buffer_array,"%d",&a);
    The above is valid if buffer_array starts with a number.

    Please help.

  7. #7
    Registered User
    Join Date
    Jun 2005
    Posts
    6,307
    All sorts of ways, but a single sscanf() call won't be an effective solution, since the buffer_array is not a fixed format.

    One way of skinning this cat is;
    Code:
    #include <string.h>
    #include <stdio.h>
    
    const char *step_over(const char *buffer_array, const char *substring)
    {
         buffer_array = strstr(buffer_array, substring);
         if (buffer_array)
         {
              buffer_array += strlen(substring);
              if (!*buffer_array) buffer_array = NULL;
         }
         return buffer_array;
    }
    
    int extract_int(const char *buffer_array)
    {
        //   assume buffer_array is not NULL and contains a zero terminated string (e.g. a string literal)
        do
        {
             int a;
             buffer_array = step_over(buffer_array, "error code ");
             if (buffer_array && sscanf(buffer_array, "%d", &a) == 1) return a;      /* we have found an int immediately following the string "error code " */
       } while (buffer_array && *buffer_array);
    
       return 0;    /*  integral value of interest not found  */
    }
    I am assuming you're happy to discard the strings like "NULL" and "STOP". Note this code also ignores other extraneous digits (e.g. the '1' in "operation1").


    Incidentally, if you are using fgets() to read your data, you will not typically be passing byte arrays in the format you describe. fgets() extracts only one line at a time (or a partial string if the buffer is insufficient). It does not pass strings containing multiple carriage returns. The code could be made simpler by assuming no more than a single line is passed (but would also need to cope with partial lines).
    Right 98% of the time, and don't care about the other 3%.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Understanding this bitwise function
    By jim_0 in forum C++ Programming
    Replies: 6
    Last Post: 12-01-2013, 03:40 AM
  2. Need help understanding function
    By peste19 in forum C Programming
    Replies: 6
    Last Post: 05-14-2012, 04:09 AM
  3. Help understanding this function...
    By Siaw Ys in forum C Programming
    Replies: 1
    Last Post: 12-02-2011, 01:03 PM
  4. need help understanding this function
    By Lince in forum C Programming
    Replies: 4
    Last Post: 08-04-2007, 10:29 AM
  5. What is wrong with my sscanf function?
    By doampofo in forum C Programming
    Replies: 5
    Last Post: 03-09-2003, 09:42 PM

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