Your loop is:
for (long i = 0; i < 6; i++) {
fscanf(fptr, "%c", &buf[i]);
fgets(buf, 50, fptr);
fprintf(stdout, "[%d]%c %d\n", i, buf[i], (int)buf[i]);
}
On the iteration when i
is 0
, you read a
into buf[0]
with scanf()
. Then, the fgets()
call reads the newline over buf[0]
and places a null byte to mark the end of the input over buf[1]
. Therefore, the fprintf(stdout, …)
call (conventionally written printf(…)
) produces the data for a newline as that's the character stored in buf[0]
.
On the iteration when i
is 1
, you read b
into buf[1]
with scanf()
. Then the call to fgets()
reads the newline over buf[0]
and places a null byte to mark the end of the input over buf[1]
. Therefore, the printing operation prints the data about the null byte as that's the character stored in buf[1]
.
On the subsequent iterations, the fgets()
call continues to write over buf[0]
and buf[1]
, but the rest of your code is looking after those characters and isn't affected.
Mixing scanf()
and fgets()
like this is dubious. It would probably be best to use just
if (scanf(fptr, " %c", &buf[i]) != 1)
break;
and drop the fgets()
completely. The leading space in the format string skips optional white space, meaning blanks, tabs and (crucially) newlines. On the first iteration, it skips nothing; on the second, it skips the newline and proceeds to read b
. And there's no confusing overwriting going on. If you add a null terminator, you'd have the string abc123
in buf
after the loop and null termination.
Alternatively, just use fgets()
and always work with buf[0]
.
Note that the cast to int
is immaterial. When a char
value is passed to printf()
or fprintf()
, it is automatically converted to int
— both the arguments buf[i]
are passed as int
, regardless of the presence or absence of a cast. See C11 §6.5.2.2 Function calls ¶7 — and ¶6 is also relevant for the definition of default argument promotions. There's room for more discussion, but it is more complex than needed to answer this question.