0

I am reading content of a file and and trying to print it, but it is giving extra garbage value.

#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h>
#include <stdlib.h>

int main() {
    long length;
    char* content;
    FILE *file = fopen("text.txt", "r");
    fseek(file, 0, SEEK_END);
    length = ftell(file);
    fseek(file, 0, SEEK_SET);
    content = (char *)malloc(length);
    fread(content, 1, length, file);
    printf("%s\n", content);
    return 0;
}

image

Maybe I have to null terminate content[length] = '\0';?

The more \n newline characters the file has at the end, the more garbage I get.

Any solution, except using calloc?

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • 1
    Yes you have to null terminate `content`, `fread` won't do that for you, why would it, it's a binary input function, not a string processing function. – john Nov 06 '22 at 16:44
  • Try `malloc(length + 1)`, in order to allow for the null character at the end. –  Nov 06 '22 at 16:45
  • i am doing it content[length] = '\0' but its not working – shashankssc02 Nov 06 '22 at 16:46
  • That's outside the boundaries though. You could do `content[length - 1] = '\0'`, but that would truncate the last character out of your desired output of course. –  Nov 06 '22 at 16:46

2 Answers2

3

If that is MSVC (clued by #define _CRT_SECURE_NO_DEPRECATE) then the file mode is probably text by default, and all the CR-LF pairs will be shrunk to a single LF when you read it. Getting the file size does not take that into account. Use the number of characters actually read to terminate the string.

content = malloc(length + 1);           // room for terminator
size_t bytes = fread(content, 1, length, file);
content[bytes] = '\0';
Weather Vane
  • 33,872
  • 7
  • 36
  • 56
  • Or, just open the file in binary mode instead: `fopen("text.txt", "rb")` – Remy Lebeau Nov 06 '22 at 17:03
  • As for the [fread manual](https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/fread), *The replacement has no effect on the file pointer or the return value.* – 273K Nov 06 '22 at 17:05
  • @273K, it does. I just read a file size `550` bytes, and `fread` reportedly read `536` bytes. The text file has 14 lines, and `536 + 14 = 550`. – Weather Vane Nov 06 '22 at 17:10
  • So, the manual lies? – 273K Nov 06 '22 at 17:11
  • @273K, perhaps it does. The proof was eating the pudding. It makes no sense to do otherwise: or the caller does not know how many bytes are in the buffer. – Weather Vane Nov 06 '22 at 17:11
1

The file content does not end with the null char. Your should reset the allocated memory buffer with 0, since it's unknown how many bytes will be read.

content = (char *)malloc(length + 1);
memset(content, 0, length + 1);
fread(content, 1, length, file);

Or you should set the data length while printing

length = fread(content, 1, length, file);
printf("%.*s\n", length, content);

See Is there a way to specify how many characters of a string to print out using printf()?

273K
  • 29,503
  • 10
  • 41
  • 64
  • Not working, the more \n at end of file more garbage value it gets – shashankssc02 Nov 06 '22 at 16:52
  • 1
    It's working. You might use another code. Ensure `file` is opened successfully. – 273K Nov 06 '22 at 16:53
  • *It's working.* No, it's not. Like the OP, you missed the text mode of the stream](https://port70.net/~nsz/c/c11/n1570.html#7.21.9.4p2): "For a text stream, its file position indicator contains unspecified information, usable by the fseek function for returning the file position indicator for the stream to its position at the time of the ftell call; the difference between two such return values is not necessarily a meaningful measure of the number of characters written or read." – Andrew Henle Nov 06 '22 at 18:32
  • @AndrewHenle Please show the exact point where I missed it. I missed it in the second snipped, but updated it before your comment. – 273K Nov 06 '22 at 19:07