简体   繁体   中英

Understanding Scanf - dealing with formatted input

I'm trying to figure out exactly how scanf works. If I code something like this:

scanf("%s %d %f", name, &age, &wage);

enter this as standard input:

james 20 34000.25

and then print out name, age, and wage respectively, I get exactly what one would expect, the same thing as I put into standard input. However, if I enter something like this:

scanf("%s/%d/%f", name, &age, &wage);

and I enter this as standard input:

james/20/34000.25

I get the string james/20/34000.25 for the string value and 0 and 0.00000 respectively for the integer and float values. I thought scanf would treat the slashes the same as it would treat the spaces in the first version. How would I get it so if a user enters a slash separated value, I can appropriately assign the values to variables?

%s matches non-whitespace characters (and it's a greedy match: it's not going to backtrack to see if some other match is possible) To match non-forward slash characters, use %[^/]

(also, note that the space character (match zero or more whitespace characters) in the scanf string has a very different behavior from a non-space non-percent character, such as '/' (match exactly '/' )

To match both the space-separated and the slash-separated inputs, you'll need a modestly complex format string:

if (scanf("%[^ /]%*1[ /]%d%*1[ /]%f", name, &age, &wage) == 3)
    ...data was read properly...
else
    ...something went wrong...

The first conversion specification is a scan set that accepts a sequence of non-blanks, non-slashes (so it will stop at the first blank or slash). It would be best to specify an upper bound on how many characters will be accepted so as to avoid stack overflow ; for example, if char name[32]; , then %31[^ /] (note the off-by-one). The second conversion specification %*1[ /] accepts a single character ( 1 ) that is either a blank or slash [ /] , and does not assign it to any variable ( * ). The third conversion specification is a standard numeric input, skipping leading blanks, allowing for negative numbers to be entered, etc. The fourth conversion specification is the same as the second, and the fifth is a standard format for a float (which means that 34000.25 with 7 significant digits is at the outer end of the range of representable values).

Note that the 'something went wrong' part has a difficult time reporting the error coherently to the user. This is why many people, myself included, recommend against using scanf() or fscanf() and prefer to use fgets() or perhaps POSIX getline to read a line from the user and then use sscanf() to analyze it. You can report the problems much more easily. Also note that the return value from scanf() is the number of successful assignments; it does not count the conversion specifications that include * .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM