One problem with this:
result = fscanf(fp, "%[^\n]s", ap->name);
is that you have an extra s
at the end of your format specifier. The entire format specifier should just be %[^\n]
, which says "read in a string which consists of characters which are not newlines". The extra s
is not part of the format specifier, so it's interpreted as a literal: "read the next character from the input; if it's an "s", continue, otherwise fail."
The extra s
doesn't actually hurt you, though. You know exactly what the next character of input: a newline. It doesn't match, and input processing stops there, but it doesn't really matter since it's the end of your format specifier. This would cause problems, though, if you had other format specifiers after this one in the same format string.
The real problem is that you're not consuming the newline: you're only reading in all of the characters up to the newline, but not the newline itself. To fix that, you should do this:
result = fscanf(fp, "%[^\n]%*c", ap->name);
The %*c
specifier says to read in a character (c
), but don't assign it to any variable (*
). If you omitted the *
, you would have to pass fscanf()
another parameter containing a pointer to a character (a char*
), where it would then store the resulting character that it read in.
You could also use %[^\n]\n
, but that would also read in any whitespace which followed the newline, which may not be what you want. When fscanf
finds whitespace in its format specifier (a space, newline, or tab), it consumes as much whitespace as it can (i.e. you can think of it consuming the longest string that matches the regular expression [ \t\n]*
).
Finally, you should also specify a maximum length to avoid buffer overruns. You can do this by placing the buffer length in between the %
and the [
. For example, if ap->name
is a buffer of 256 characters, you should do this:
result = fscanf(fp, "%255[^\n]%*c", ap->name);
This works great for statically allocated arrays; unfortunately, if the array is dyamically sized at runtime, there's no easy to way to pass the buffer size to fscanf
. You'll have to create the format string with sprintf
, e.g.:
char format[256];
snprintf(format, sizeof(format), "%%%d[^\n]%%*c", buffer_size - 1);
result = fscanf(fp, format, ap->name);