So i had an exam, and one of the excercies included to scan names from a binary file. I had used fscanf()
, but my prof told me that i cant use fscanf in binary files. but why? my program works just fine even if i do so.

- 52,653
- 6
- 59
- 97

- 43
- 1
- 2
- 9
-
1Please give an example of how would you use `fscanf()` with a binary file, can you? – Iharob Al Asimi Feb 13 '15 at 18:48
-
1FILE *file=fopen("names.bin", "rb"); char str[20]; while(!feof(file)) { fscanf(file, "%s", str); printf("%s", str); } – suspicious Feb 13 '15 at 18:51
-
1first of all `while (!foef(file))` [is always wrong](http://stackoverflow.com/questions/5431941/while-feof-file-is-always-wrong), and even if the file was a text file `fscanf(file, "%s", str)` would scan names that don't have spaces embedded in them. – Iharob Al Asimi Feb 13 '15 at 18:56
-
1Also, if you were to store integers or some other kind of value, then `fscanf()` wouldn't work, it works when the binary data is text, just because the byte represantation of text is just the text itself. – Iharob Al Asimi Feb 13 '15 at 19:00
-
@iharob iharob, why is feof() wrong? – suspicious Feb 13 '15 at 19:01
-
@S.Morgenstern , but how can i use fread() if i dont know the size of the strings that Im reading? – suspicious Feb 13 '15 at 19:01
-
@suspicious read the link please – Iharob Al Asimi Feb 13 '15 at 19:02
-
@iharob thanks man, it was actually helpful – suspicious Feb 13 '15 at 19:12
-
@S.Morgenstern well it was like : name surname name surname. So it is actually true that to use fread, i have to know the size of the string that i am reading? because if it so, i suppose i should have taken a random string size (supposing that the file was previously written using that size). – suspicious Feb 13 '15 at 19:16
-
I think my previous comment was incorrect. I can only get `fscanf` to work if I send it text separated by spaces. But that’s just a plain text file. Were `name` and `surname` separated by spaces, or NUL bytes? Since `fread` needs a size, and you don’t know how long the string is, you could read one byte at a time instead, and stop when you reach whatever character marks the end of the string. – yellowantphil Feb 13 '15 at 19:19
-
@S.Morgenstern thank you. you have been very helpful. – suspicious Feb 13 '15 at 19:22
-
@S.Morgenstern that's not really a good approach, but you make a point, also, note that `fscanf()` does not have such requirements, the only requirement is that the scanned data must be text, and then you are free to build the right format specifier to read it. – Iharob Al Asimi Feb 13 '15 at 19:29
-
Hmm, at least two of my previous comments were wrong. If you use `fscanf(file, "%s", str)`, it will read anything in the file until it hits whitespace. Whitespace does _not_ include a NUL byte, so those will get read into `str` too. But if you try to `printf("%s", str)`, `printf` will stop at the first NUL byte, even if there is more text in `str`. So if your file contains NUL bytes, `fscanf` is bad news, even though it might appear to work. For your specific case, I would need to know more about the format of your binary file to say whether `fscanf` is a bad idea. – yellowantphil Feb 13 '15 at 19:29
-
`fscanf()` will add the `nul` byte, that's why I've used `fscanf(file, "%63s", entry.name);` because `entry.name` can hold `64` characters, so they will be `63` and the `'\0'`. – Iharob Al Asimi Feb 13 '15 at 19:30
-
@S.Morgenstern reading one character at a time is not always a good solution, sometimes it is of course. – Iharob Al Asimi Feb 13 '15 at 19:31
-
@iharob Yes, I just couldn’t think of anything better. Reading variable-length strings in a binary file is trickier than I thought it would be at first. – yellowantphil Feb 13 '15 at 19:32
-
@S.Morgenstern It requires a stablished convetion that would let you know what is the length of the string, the technique that I like is `struct Data {int32_t length; char *string};` because you can find out what the size of the string is by just reading the first 4 bytes of each record, you should of course be careful with endianness when implementing this kind of solution. – Iharob Al Asimi Feb 13 '15 at 19:39
1 Answers
I admit that I didn't find a way to explain what is wrong with fscanf()
and binary files that would be understood easily, but here is an example of how the binary
file generated is read erroneously by fscanf()
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Entry
{
char text[64];
int age;
};
int main()
{
FILE *file;
struct Entry entry;
file = fopen("data.bin", "wb");
if (file == NULL)
return -1;
entry.age = 30;
memset(entry.text, 0, sizeof(entry.text));
strcpy(entry.text, "Iharob Al Asimi");
fwrite(&entry, sizeof(entry), 1, file);
entry.age = 22;
memset(entry.text, 0, sizeof(entry.text));
strcpy(entry.text, "Claudio Urdaneta");
fwrite(&entry, sizeof(entry), 1, file);
entry.age = 29;
memset(entry.text, 0, sizeof(entry.text));
strcpy(entry.text, "Dayana Orozco");
fwrite(&entry, sizeof(entry), 1, file);
fclose(file);
file = fopen("data.bin", "rb");
if (file == NULL)
return -1;
fprintf(stderr, "with fscanf()\n");
/* this is intentionally == 1 to prove the point */
while (fscanf(file, "%63s%d", entry.text, &entry.age) == 1)
fprintf(stderr, "\t%s, %d\n", entry.text, entry.age);
rewind(file);
fprintf(stderr, "with fscanf()\n");
while (fread(&entry, sizeof(entry), 1, file) == 1)
fprintf(stderr, "\t%s, %d\n", entry.text, entry.age);
fclose(file);
return 0;
}
The problem is that fscanf()
will scan for text and match against the specifiers you pass to it.
But a binary file is just a bunch of bytes stored with a given structure, in the example above we write 64 + sizeof(int)
bytes per record, one of the items is just text so reading bytes with fscanf()
works as expected and it of course stops at the whitespace character.
But then the number has no text represantation in the file, and hence you cannot read it with fscanf()
.
Also, please note this
while (fscanf(file, "%63s%d", entry.text, &entry.age) == 1)
the correct way of doing it is
while (fscanf(file, "%63s%d", entry.text, &entry.age) == 2)
but then nothing will be printed because the integer wont be matched.
So when working with binary files you need
fread()
/fwrite()
whereas when the data is just text
fprintf()
/fscanf()
will be good.

- 52,653
- 6
- 59
- 97