0

well While I was writing the question I found this answer

which gives the following solution to make it skip that line fscanf(config_file, "%*[^\n]\n"); It worked But I don't really understand the whole thing yet for example why there is two NEWLINE characters in the pattern what each of them represent and if there's more to know about this patterns

the reference in the answer gives a brief explanation about what this characters mean But I would like a more complete explanation,

After some searching I didn't manage to put my hands on any complete reference on this characters So if someone can provide a reference to read from or something. would be appreciated

Susano
  • 230
  • 2
  • 9
  • 1
    See (draft of) the specification: [http://www.iso-9899.info/n1570.html#7.21.6.2](http://www.iso-9899.info/n1570.html#7.21.6.2) – MikeCAT Nov 27 '20 at 23:18
  • 2
    Don't do it with `fscanf()`. Use `fgets()` to read a line at a time, so you can just call this an extra time to skip a line. You can then parse the lines that you want to process with `sscanf()`. – Barmar Nov 27 '20 at 23:20
  • 1
    `%*[^\n]\n` reads (but does not assign) any characters other than a `\n` newline, then skips over any following whitespace (newlines, spaces, tabs). See the scanf format specifiers [here](https://en.cppreference.com/w/cpp/io/c/fscanf) for example. – dxiv Nov 27 '20 at 23:51
  • 1
    Don't do it with either `fscanf` or `fgets`. Use `fgetc` in a loop. With `fgets`, you have to add logic to ensure that you've read a full line, and that is more complex than the `fgetc` loop. – William Pursell Nov 27 '20 at 23:53
  • 2
    @dxiv "%*[^\n]\n reads (but does not assign) any characters other than a \n newline, then skips over any following whitespace (newlines, spaces, tabs)." is true when the first character is not a `'\n'`. In that corner case, "skip a line" this way fails. – chux - Reinstate Monica Nov 28 '20 at 02:33
  • @chux-ReinstateMonica Right. I should have made more clear the implied "*if present*" after "*reads*". – dxiv Nov 28 '20 at 03:20

1 Answers1

3

How to make fscanf function skip a line?

I think you could:

void skip_nl(FILE *f) {
    char c[2];
    fscanf(f, "%1[\n]", c) == 1 || fscanf(f, "%*[^\n]%*1[\n]");
}

Note that scanning %*[^\n] will fail when there will be an empty line ("fail", as in scanf will stop scanning). So if there is an empty line, %*[^\n] will scan nothing and scanf will just return. So an empty line has to be handled specially, and fscanf return value is used to detect if the scan was succesfull or not. Note that %* discarded scanning does not increment scanf return value. So first scanf("%1[\n]" with a temporary unused buffer just "detects" (and discards) an empty line. If the line is not an empty line, then %*[^\n] scans and discards one or more non-newline characters and after that %*1[\n] discards a single newline character. If you are sure that the input will not be just a newline, then %*[^\n]%*1[\n] is fine. Tested on godbolt.

But really writing the following is really not that hard...:

for (int c; (c = getc(f)) != EOF && c != '\n'; ) {}
KamilCuk
  • 120,984
  • 8
  • 59
  • 111
  • Well I needed to skip unempty lines on occurence of specific characters which I think fscanf and fseek will be a better choice for me than your loop, but thanks anyway – Susano Nov 28 '20 at 00:28
  • 1
    Nice `||` doing the `fscanf(f, "%1[\n]", c)` first (UV), yet `fscanf(f, "%1[\n]", c) != 0` is better to quit on end-of-file or input error as well as `"\n"`. Best not to continue when input error occurs. – chux - Reinstate Monica Nov 28 '20 at 02:27