In the way that you're using it, fwrite
is writing "binary" output, which is a byte-for-byte representation of your struct test
as in memory. This representation is not generally human-readable.
When you write
struct test test1 = {"name", 12, 12.334};
you get a structure in memory which might be represented like this (with all byte valuess in hexadecimal):
test1: str: 6e 61 6d 65 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
num: 0c 00 00 00
fnum: 10 58 45 41
Specifically: 0x6e
, 0x61
, 0x6d
, and 0x65
are the ASCII codes for the letters in "name"
. Your str
array was size 20, so the string name
is 0-terminated and then padded out with 15 more 0 characters. 0x0c
is the hexadecimal representation of the number 12, and I'm assuming that type int
is 32 bits or 4 bytes on your machine, so there are 3 more 0's there, also. (Also I'm assuming your machine is "little endian", with the least-significant byte of a 4-byte quantity like 0x0000000c
coming first in memory.) Finally, in the IEEE-754 format which your machine uses, the number 12.334 is represented in 32-bit single-precision floating point as 0x41455810
, which is again stored in the opposite order in memory.
So those 28 bytes (plus possibly some padding, which we won't worry about for now) are precisely the bytes that get written to the screen, or to your file. The string "name" will probably be human-readable, but all the rest will be, literally, "binary garbage". It just so happens that three of the bytes making up the float number 12.334, namely 0x58
, 0x45
, and 0x41
, correspond in ASCII to the capital letters X
, E
, and A
, so that's why you see those characters in the output.
Here's the result of passing the output of your program into a "hex dump utility:
0 6e 61 6d 65 00 00 00 00 00 00 00 00 00 00 00 00 name............
16 00 00 00 00 0c 00 00 00 10 58 45 41 .........XEA
You can see the letters name
at the beginning, and the letters XEA
at the end, and all the 0's and other binary characters in between.
If you're on a Unix or Linux (or Mac OS X) system, you can use tools like od
or hexdump
to get a hex dump similar to the one I've shown.
You asked about the "count" argument to fwrite
. fwrite
is literally designed for writing out binary structures, just like you're doing. Its function signature is
size_t fwrite(void *ptr, size_t sz, size_t n, FILE *fp);
As you know, ptr
is a pointer to the data structure(s) you're writing, and fp
is the file pointer you're writing it/them to. And then you're saying you want to write n
(or 'count') items, each of size sz
.
You called
fwrite(&test1, sizeof(test1), 1, fp);
The expression sizeof(test1)
gives the size of test1
in bytes. (It will probably be 28 or so, as I mentioned above.) And of course you're writing one struct, so passing sizeof(test1)
and 1
as sz
and n
is perfectly reasonable and correct.
It would also not be unreasonable or incorrect to call
fwrite(&test1, 1, sizeof(test1), fp);
Now you're telling fwrite
to write 28 bytes, each of size 1. (A byte is of course always size 1.)
One other thing about fwrite
(as noted by @AnttiHaapala in a comment): when you're writing binary data to a file, you should specify the b
flag when you open the file:
fp = fopen("test.txt", "wb");
Finally, if this isn't what you want, if you want human-readabe text output instead, then fwrite
is not what you want here. You could use something like
printf("str: %s\n", test1.str);
printf("num: %d\n", test1.num);
printf("fnum: %f\n", test1.fnum);
Or, to your file:
fprintf(fp, "str: %s\n", test1.str);
fprintf(fp, "num: %d\n", test1.num);
fprintf(fp, "fnum: %f\n", test1.fnum);