Why is my simple C program dumping garbage on stdout?

Consider the following simple C program, which reads a file into a buffer and maps this buffer to the console:

#include<stdio.h> main() { FILE *file; char *buffer; unsigned long fileLen; //Open file file = fopen("HelloWorld.txt", "rb"); if (!file) { fprintf(stderr, "Unable to open file %s", "HelloWorld.txt"); return; } //Get file length fseek(file, 0, SEEK_END); fileLen=ftell(file); fseek(file, 0, SEEK_SET); //Allocate memory buffer=(char *)malloc(fileLen+1); if (!buffer) { fprintf(stderr, "Memory error!"); fclose(file); return; } //Read file contents into buffer fread(buffer, fileLen, 1, file); //Send buffer contents to stdout printf("%s\n",buffer); fclose(file); } 

The file that he will read simply contains:

Hello World!

Output:

Hello World! ²²²²▌▌▌▌▌▌▌↔☺

Some time has passed since I did something meaningful in C / C ++, but usually I assume that the buffer is allocated more than necessary, but this does not seem to be the case.

fileLen ends at 12, which is accurate.

Now I think that I should just display the buffer incorrectly, but I'm not sure what I'm doing wrong.

Can someone tell me what I'm doing wrong?

+8
c file-io
Nov 03 '08 at 22:43
source share
5 answers

You need a NUL-complete line. Add

 buffer[fileLen] = 0; 

before printing it.

+38
Nov 03 '08 at 22:45
source share

The JesperE approach will work, but you may be interested to know if there is an alternative way to handle this.

You can always print a string of known length, even if there is no NUL terminator, specifying the length of printf as the precision for the string field:

 printf("%.*s\n", fileLen, buffer); 

This allows you to print a string without changing the buffer.

+28
Nov 03 '08 at 23:14
source share

JesperE correctly refers to the nul-term problem in your example, I’ll just add that if you are processing text files, it would be better to use fgets () or something like that, since this will correctly handle newline strings on different platforms and will always nul-end the line for you. If you really work with binary data, you do not want to use printf () to output data, because printf functions expect a string, and a zero byte in the data will truncate the output.

+8
Nov 03 '08 at 23:13
source share

Your approach to determining the file size by finding the end of the file and using ftell() incorrect:

  • If this is a text file opened without "b" in the second parameter for calling fopen() , then ftell() may not indicate the number of characters that you can read from the file. For example, windows use two bytes for the end of a line, but when reading it is one char . In fact, the return value of ftell() for streams opened in text mode is only useful for fseek() calls, and not for determining file size.
  • If it is a binary file opened with "b" in the second parameter of fopen() , then in the C standard it says:

    Setting the file position indicator to the end of the file, as in the case of fseek(file, 0, SEEK_END) , has undefined behavior for a binary stream (due to possible terminating null characters) or for any stream with a state-dependent encoding, which is not finite , end in the initial state of shear.

So what you do will not necessarily work in the C standard. It is best to use fread() to read, and if you need more memory, use realloc() . Your system can provide mmap() or it can provide guarantees regarding the installation of the file position indicator at the end of the file for binary streams & mdash, but relying on them is not portable.

See also this C-FAQ: What is the difference between text and binary I / O? .

+2
Jan 16
source share

You can use calloc instead of malloc to allocate already initialized memory. calloc takes an additional argument. This is useful for distributing arrays; the first calloc parameter indicates the number of elements in the array for which you want to allocate memory, and the second argument is the size of each element. Since the size of a char always 1, we can simply pass 1 as the second argument:

  buffer = calloc (fileLen + 1, 1); 

In C, there is no need to specify the return value of malloc or calloc . The above ensures that the line will be terminated to zero, even if the reading of the file ended prematurely for any reason. calloc takes longer than malloc because it needs to zero out all the requested memory before giving it to you.

0
Jan 16 '10 at 2:56
source share



All Articles