1

Hi I am reading some code and this line has been used:

scanf("%s%*c",dati[i].part);

What does %s%*c do and why not just use %s?

  • 1
    They want to remove the next character from the input, possibly a trailing newline. IMO this is a horrible practice. It is better to filter *leading* whitespace, most of which is automatic with `scanf` (but not all). – Weather Vane Jan 18 '20 at 18:03
  • [%*c in scanf() - what does it mean?](https://stackoverflow.com/q/11542010) – P.P Jan 18 '20 at 18:04

2 Answers2

3

What does %s%*c do

The %s has the same meaning as anywhere else -- skip leading whitespace and scan the next sequence of non-whitespace characters into the specified character array.

The %*c means the same thing as %c -- read the next input character, whatever it is (i.e. without skipping leading whitespace) -- except that the * within means that the result should not be assigned anywhere, and therefore that no corresponding pointer argument should be expected. Also, assignment suppression means that scanf's return value is not affected by whether that field is successfully scanned.

and why not just use %s?

We cannot say for sure why the author of the code in which you saw it used %s%*c, except for the unsatisfying "because that's what the author thought was appropriate." We have no context at all for making any other judgement.

Certainly the actual effect is to consume the next input character after the string, if any. If there is such a character then it will necessarily be a whitespace character, else it would have been scanned by the preceding %s directive. We might therefore speculate that the author's idea was to consume a trailing newline.

There are at least two problems with that:

  1. The next character might not be a newline. For example, there might be trailing space characters before a newline, in which case the first of those space characters would be consumed, but the newline would remain in the stream. If that's a genuine problem then %*c does not reliably solve it.

  2. In practice, it's not very useful. Most scanf directives are like %s in that they automatically skip leading whitespace, including newlines. The %*c serves only to confuse if the next directive that will be processed is any of those. Moreover, it is possible for a scanf format to explicitly express that a run of whitespace at a given position should be skipped, and it is clearer to make use of that in conjunction with the next directive to be processed if that next directive is one of those that don't automatically skip whitespace (and whitespace skipping is in fact desired).

That doesn't mean that assignment suppression generally or %*c specifically is useless, mind. It's just trying to use that technique to attempt to consume trailing newlines that is poorly conceived.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
1

The %* format specifier in a scanf call instructs the function to read data in the following format (c in your case) from the input buffer but not to store it anywhere (i.e. discard it).

In your specific case, the %*c is being used to read and discard the trailing newline character (added when the user hits the Enter key), which will otherwise remain in the input buffer, and likely upset any subsequent calls to scanf.

Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
  • 2
    The `%*c` certainly reads and discards the first character of the whitespace that deliminated the preceding `%s` field, unless it was terminated by EOF. It is plausible that the intent is to skip a newline, but that approach is not certain to be effective, and it is by no means clear that leaving a newline in the buffer would interfere with subsequent `scanf` calls. *Most* `scanf` field directives skip newlines along with other leading whitespace. – John Bollinger Jan 18 '20 at 18:57
  • `"%*1[\n]"` reads and discards the a trailing newline. `"%*c"` is not limited to that. – chux - Reinstate Monica Jan 18 '20 at 20:16