scanf error handling C

2020-02-29 10:25发布

问题:

Say If i want an input to be

[Name] [Name]

How would I detect

[Name] [Name] [Name] 

and return error?

Here is what I have so far,

char in[20];
char out[20];
scanf(" %s %s", out, in);

回答1:

This is homework, so you might be required to work under certain (arbitrary) restrictions. However, the phrase "scanf error handling" is something of an oxymoron in the C programming language.

The best way to do this is to read in a line/other suitable chunk and parse it with C string functions. You can do it in one line of scanf but there are many drawbacks:

  1. You can guard against buffer overflows, but if a buffer isn't large enough you can't recover.
  2. You can specify specific character ranges for your strings, but it starts to look a little regexy, and the behavior of the "%[" format of scanf isn't mandated in the standard.
  3. You can check for a third name, but the code looks unintuitive - it doesn't look like you only want two names, it looks like you want three. scanf also gives you very little control over how you handle whitespace.

EDIT: I initially thought from your question that the names were contained in brackets (a la "[Bruce] [Wayne]") but it now appears that was merely your convention for denoting a placeholder.

Anyway, despite my intense dislike of scanf, it has its uses. The biggest killer (for me) is the inability to distinguish between line endings and simple space separation. To fix that, you can call fgets to read the data into a buffer, then call sscanf on the buffer. This gives you both a) safer reading (scanf messes with the ability of other more straightforward functions to read from a buffer) and b) the benefits of scanf formats.

If you have to use scanf, your format basically be this:

" %s %s %s"

With the third being undesirable. As @Constantinius's answer shows, you'd need to read data into three buffers, and check whether or not the third passed. However, if you're reading multiple consecutive lines of this data, then the first entry of the next line would satisfy the third slot, falsely giving you an error. I highly recommend using fgets and sscanf or ditching the sscanf for more precise manual parsing in this case.

Here's a link to the fgets man page if you missed the one I snuck in earlier. If you decide to ditch sscanf, here are some other functions to look into: strchr (or strspn, or strcspn) to find how long the name is, strcpy or memcpy (but please not strncpy, it's not what you think it is) to copy data into the buffers.



回答2:

scanf returns the number of validly converted arguments. So in your first case, the return value would be 2, in the latter case 3.

To check the right amount of parameters, this might help:

char in[20];
char out[20];
char error[20];
int check;

check = scanf(" %s %s %s", out, in, error);
if(check != 2)
{
    // TODO: error handling
}

EDIT: now it should be working, see comments below.

Of course, as stated by other posters: scanf is not considered a quite safe function since buffer overflows can occur, and you should avoid using it. It is better to read the inputs to a buffer with fgets() and the try to parse the arguments you want.