Home > Blockchain >  Use sscanf to process variable-format output
Use sscanf to process variable-format output

Time:08-19

This is a program ,15.5,in the book called Pointers On C.I can't understand what this program want to do.

#include<stdio.h>
#include<stdlib.h>
#define DEFAULF_A 1
#define DEFAULF_B 2
void function(char *buffer)
{
    int a,b,c;
    if(sscanf(buffer,"%d %d %d",&a,&b,&c)!=3)
    {
        a=DEFAULF_A;
        if(sscanf(buffer,"%d %d",&b,&c)!=2)
        {
            b=DEFAULF_B;
            if(sscanf(buffer,"%d",&c)!=1)
            {
                fprintf(stderr,"Bad input:%s",buffer);
                exit(EXIT_FAILURE);
            }
        }
    }
}//***the title of the program is Use sscanf to process variable-format output***

If I suppose the first three number in buffer is 1,2 and 3.

  1. List item The sscanf at the second if assigns 1 to B that should have been assigned to A and assigns 2 to C that should have been assigned to B.So why not just throw out the &c and leave the &a in sscanf,like this
c=DEFAULF_A;
if(sscanf(buffer,"%d %d",&a,&b)!=2)
  1. List item And why does the exit(EXIT_FAILURE) appear in the third if?When the exit(EXIT_FAILURE) appear in the third if,it mean there is a problem with the first read and the second and the third reads don't know.But when it comes this case sscanf(buffer,"%d %d %d",&a,&b,&c)!=3,the program is also wrong.
  2. List item So what this program want to do? Due to I just started to learn CS,I only konw a little about C language,and lack other basic computer knowledge,please answer in a way that is easy to understand.Thanks in advance. This is a example in Pointers On C .This program might correspond to this sentence that "the latter is used to convert the expected number of values.

CodePudding user response:

  1. [] The sscanf at the second if assigns 1 to B that should have been assigned to A and assigns 2 to C that should have been assigned to B.So why not just throw out the &c and leave the &a in sscanf,like this

    c=DEFAULF_A;
    if(sscanf(buffer,"%d %d",&a,&b)!=2)
    

Because that's (apparently) not the desired behavior. The program is assigning read values to the rightmost subset of variables (a, b, c), so if only two values are provided then they go to b and c, and if only one is provided then it goes to c. The variables that don't get read values assigned to them are assigned default values instead. Your proposed alternative does not achieve the same thing.

And this is in fact the distinguishing characteristic of the function presented -- the "trick", if you will. It would indeed be simpler to write a straight left-to-right style matchup of values to variables.

Nevertheless, the function is needlessly complicated. Myself, I would not write it with three separate sscanf calls, because you can get everything you need from just one. I would write the function something like this:

#define DEFAULT_A 1
#define DEFAULT_B 2

void function(char *buffer) {
    int a, b, c, num_fields;

    num_fields = sscanf(buffer, "%d %d %d", &a, &b, &c);

    switch (num_fields) {
        case 3:
            // three values read and assigned.  nothing to see here.
            break;
        case 2:
            // only two values read (into variables 'a' and 'b')
            // shift them to the correct variables and assign a default to 'a'
            c = b;
            b = a;
            a = DEFAULT_A;
            break;
        case 1:
            // only one value read (into variable 'a')
            // shift it to the correct variable and assign defaults to the others
            c = a;
            b = DEFAULT_B;
            a = DEFAULT_A;
            break;
        default:
            fprintf(stderr, "Bad input: %s\n", buffer);
            exit(EXIT_FAILURE);
    }
}
  1. [] And why does the exit(EXIT_FAILURE) appear in the third if?When the exit(EXIT_FAILURE) appear in the third if,it mean there is a problem with the first read and the second and the third reads don't know.But when it comes this case sscanf(buffer,"%d %d %d",&a,&b,&c)!=3,the program is also wrong.

The return value of sscanf reports on two things:

  1. how many scanf directives resulted in values being successfully read from the input, converted to the indicated data type, and assigned to variables; and

  2. whether any kind of system error was encountered (very unlikely for sscanf(), but this is shared with scanf(), for which it is a genuine possibility).

You seem to have the second one in mind, but it is the first that the program is mainly relying upon. It is using the return value to determine how many of the variables were assigned values. That the first attempt does not assign all three does not imply that the second will not assign two, or the third, one. But of course you're right that the program is somewhat redundant. As I demonstrate above, only one sscanf() call is needed.

  1. [] So what this program want to do?

Nitpick: it's just one function, not a complete program.

Technically, because it doesn't do anything with the values it parses out of the string, all it does is report on whether the string pointed to by the function argument starts with a text representation of at least one decimal integer, optionally preceded by any number of whitespace characters (spaces, tabs, etc.). If so, it prints nothing. If not, it prints an error message.

But what you're probably looking for is the explanation I provided in response to your first numbered question.

CodePudding user response:

Seeing how you are essentially asking 'What does this program' do: It is essentially performing a 'default initialization for not entered values'.

Another (more efficient) way to achieve (much) the same thing is:

#include<stdio.h>
#include<stdlib.h>
#define DEFAULF_A 1
#define DEFAULF_B 2
void function(char *buffer)
{
    int a,b,c;
    switch (sscanf(buffer,"%d %d %d",&a,&b,&c))
    {
        case 1:
            b = DEFAULF_B; //Only one has been entered, assign default to 'b'.
        //Falls through
        case 2:
            c = DEFAULF_A; //Only two have been entered, assign default to 'c'.
        //Falls through.
        case 3: break;    //All three have been entered, do nothing.
        default: 
            exit(EXIT_FAILURE); //None have been entered -> Abort the program.
        break;
    }
}
  • If buffer contained 3 numbers, all three numbers are kept and no defaults are applied.
  • If buffer contained 2 numbers, the two numbers are kept (in your code that's b and c, in mine it's a and b) and DEFAULF_A is assigned to the remaining variable.
  • If buffer contained 1 number, that number is kept (c for you, a in my example) and the other two get assigned DEFAULF_A and DEFAULF_B respectively.
  • If buffer contained no number at all, your program gets terminated with the return code 'EXIT_FAILURE', which a calling program could fetch.

CodePudding user response:

The program examines contents from a buffer, and tries to read three values from it, for example:

1 2 3

If the first sscanf finds three numbers, it reads them all. If only two are found, it assigns default value to a and tried to read two numbers. If only one is found, it assigns default value to b and tries to read one number. If there are no numbers, the program exits, because there is no default value for c.

So if we reach exit(), it means there were neither 3, 2, or 1 numbers in the buffer. If one of the if clauses succeeded, further ones are not executed.

It is important to realize that sscanf always starts from the beginning of the buffer. So if it reads for example 1 2 in the first call, but cannot find the third one, the buffer still contains the same data during the second call, and two numbers can be read.

Regarding your question 1: Why are two numbers considered as "b and c", rather than "a and b"? This is simply the way the programmer wanted the program to work. They could have as easily set a default value for c and considered the two numbers as "a and b".

Regarding your question 2: What if the output is completely invalid, and the third read will fail? In that case, we know that the first and second reads will fail as well, so we can safely put the error handling after the third one.

CodePudding user response:

I don't see a mistake in the function as such. Would be nice to know how do you set the buffer outside. Maybe something with the terminating 0? If sscanf thinks that there are more values that 3, your function WILL fall into the failure case.

  •  Tags:  
  • c
  • Related