-2

I'm writing an array of 3 integers to a file using C's fwrite function but when opening the output file with gedit (using Unicode UTF-8), I get the following error:

There was a problem opening the file.  The file you opened has invalid characters.  If you continue editing this file, you could corrupt the document.

Here's the relevant code snippet:

char* imageFile = "image.txt";
FILE* imageFilePtr = fopen(imageFile, "w");

int scores[3] = {69, 70, 71};
fwrite(scores, sizeof(int), sizeof(scores), imageFilePtr);

When I use a hexadecimal reader such as "xxd", I get the following in my terminal:

0000000: 4500 0000 4600 0000 4700 0000 7031 7108  E...F...G...p1q.
0000010: 0830 7108 2987 0408 2087 0408 0460 cebf  .0q.)... ....`..
0000020: 0100 0000 0000 0000 0000 0000 0000 0000  ................

Keep in mind that the in my environment, sizeof(int) is 4 bytes. Thus, I can see how 69, 70, and 71 in decimal are being printed to the file as 45, 46, and 47 in hex as xxd shows. But, where are all the other bytes after "4700 0000" coming from? And, why can't I open the output file, "image.txt", with a text editor to see a file that shows the decimal numbers, 69, 70, and 71 written inside?

Vee
  • 1,821
  • 3
  • 36
  • 60

2 Answers2

5
fwrite(scores, sizeof(int), sizeof(scores), imageFilePtr);
                            ^^^^ Wrong

In your case, sizeof(scores) is sizeof(int)*3. What you need is just 3. You can use:

fwrite(scores, sizeof(int), 3, imageFilePtr);

or to be more robust, use:

fwrite(scores, sizeof(int), sizeof(scores)/sizeof(int), imageFilePtr);

You may also use:

fwrite(scores, 1, sizeof(scores), imageFilePtr);

or

fwrite(scores, sizeof scores[0], sizeof scores/sizeof scores[0], imageFilePtr);
R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • 1
    or `fwrite(scores, 1, sizeof(scores), imageFilePtr);`. – Barmar Oct 07 '15 at 21:44
  • 1
    I'll toss in another "may also use" suggestion: `fwrite(scores, sizeof scores[0], sizeof scores/sizeof scores[0], imageFilePtr);`. Allows the return value to be the number of elements of `scores[]` in the rare case when more than 0 but less than all. But that is more WET than DRY with [@Bamar](http://stackoverflow.com/questions/33002756/c-fwrite-cant-open-file-because-it-contains-invalid-characters#comment53830809_33002815) – chux - Reinstate Monica Oct 07 '15 at 21:52
  • Thanks, @Sahu. Your solution for fwrite worked perfectly. I'm accepting waterjuice's answer below because he provided a clearer explanation and addressed the fact that fwrite creates a binary file (which is why I couldn't open the file with a text editor) while fprintf creates a text file. – Vee Oct 08 '15 at 16:49
  • @Vee, that's perfectly alright. It's more important that you understand the issues and correct them appropriately. – R Sahu Oct 08 '15 at 16:58
1

There are two problems I can see here. One is that you are trying to open a binary file in a text editor. The second is that you have a buffer read overflow when writing the binary file. I'll address the second one first.

the fwrite function takes a "size of element" and a "count of elements" as parameters. You have put the size of element as sizeof(int) which is correct, however for the count you have done sizeof(scores) which is actually 3*sizeof(int), whereas you actually need the value 3. Assuming int size is 4 (32bit) then the count value is being set at 12. Which means it is trying to write 48 bytes to the file instead of 12. The additionally 36 bytes is a read overflow on the stack.

To get the number of elements in array you can use: sizeof(scores)/sizeof(scores[0]).

fwrite(scores, sizeof(int), sizeof(scores)/sizeof(scores[0]), imageFilePtr);

I would use a macro for this so I could go

fwrite(scores, sizeof(int), NumOfElements(scores), imageFilePtr);

where NumOfElements is defined as:

#define NumOfElements(Array) (sizeof(Array)/sizeof(Array[0]))

Now for the first problem. I believe you were trying to write 3 integers into a text file. The fwrite function writes binary data. What you want to use is fprintf. This works the same way as printf but will let you write to a file. However you can not write an array of numbers with one fprintf, so you would have to have a loop.

for( i=0; i<NumOfElements(scores); i++ )
{
    fprintf( imageFilePtr, "%u\n", scores[i] );
}

This will write each number into the file on a seperate line.

waterjuice
  • 829
  • 5
  • 14
  • 1) By using `fwrite(scores, sizeof scores[0], ...`, code can avoid getting the type wrong. 2) `scores[i]` is an `int`, so `fprintf( imageFilePtr, "%d\n", scores[i] );` or make `scores[i]` an `unsigned`. 3) like the macro `NumOfElements` – chux - Reinstate Monica Oct 08 '15 at 02:11
  • Ah good point on the %d vs %u. My mistake, I always use unsigned ints 99.9% of time and so was just used to that. – waterjuice Oct 08 '15 at 02:29
  • Thanks for the explanation, @waterjuice! – Vee Oct 08 '15 at 16:49