uidzer0 wrote:
[edited slightly, and trimmed heavily]
You should include a newline to immediately flush the output to the
connected device.
Actually, in this case, there *is* an included newline (usually):
it is in the string stored in "line". Remember that fgets()
keeps the newline at the end of the input line. There are only
two cases in which the newline is omitted:
1) The input line was so long that it had to be split. The
fgets() function writes the initial part of the input
line into the array ("line", in this case), and leaves
the remaining part of the input line in the input stream.[%]
Subsequent fgets() calls will read and consume more of
that line, up to and including the newline that terminates
it. Those partial-and-eventually-complete lines (including
the single terminating newline) will be passed to the
printf() call, so the output will re-construct the original
input.
2) The input file ended without a terminating newline, and the
underlying implementation chooses to handle such files by
reporting the final line without a terminating newline. In
this case, the next fgets() call will return NULL, with the
reason for failure being "reached end of file" (i.e., this
will set feof(fp)). In this case, it is usually probably best
to output an unterminated text line, so as to mimic the input.
There is no guarantee that the implementation will be able
to produce that output line (perhaps the input file is
coming from a file system that supports partial final lines,
while the output file is being written on one that does
not), but unless you have something specific in mind, adding
a newline terminator (to make the output "valid") is, at the
least, changing the input.
So in this *particular* case -- reading an input file and copying
it to the standard output -- using printf with "%s" and no newline
is probably right. (Or, equivalently, one can use fputs(line,stdout)
in the loop body. The fputs() and puts() functions have the same
newline relationship, in this case, as the fgets() and gets()
functions: the old, less-thought-out, less-usable[$] gets() and
puts() fiddle with the data, while the newer, more-thought-out
fgets() and fputs() functions leave it unchanged, as much as
possible. In less precise, but more memorable, words, "gets and
puts delete and add a newline respectively; fgets and fputs do
not.")
-----
[%] This assumes the implementation is actually capable of handling
very long lines. Text files, on some systems, have line length
restrictions. If the line[] array has size 4096, but the
underlying system never has lines longer than 1023 characters,
there can never be a line long enough to split. In some
particularly old and klunky systems, it is even possible that
the input file might have lines longer than the input methods
can handle, in which case overlong input lines might be truncated
before the C system ever really "sees" them. In both cases, the
C compiler is effectively hobbled by the system. There is no
portable way around this problem, though, so one might as well
ignore it, in general. (In specific cases, one might be able
to open the text file as a "binary" file and decode the "true
intent" from the raw record-data. If the raw data is encoded
-- e.g., some form of ISAM or VSAM -- doing this can be rather
complex.)
[$] In the case of gets(), "nearly unusable". While its newline
removal is sometimes handy, you can only use it safely if you
can somehow verify the input data before reading it. On some
systems you could do a pre-scan of the entire file, with the
file somehow locked against changes, but this is nonportable
and, if not a bad idea for other reasons, at the least, I would
call it "icky".
One might as well just use fgets(), or
code similar to Chuck Falconer's ggets(), or some such.