0

I have the following program below that compiles without error. My goal is to read the contents of a file into an array called str. However, this array needs to be dynamic and memory must be reallocated each line, as the file length is unknown.

int i;
char *str;
    
FILE *fptr = fopen(filename,"r"); //Open the required file in read mode
for(i = 0; i < 3; i++) {
    fgets(str, sizeof(str), fptr);
    printf("%s", str);
} 

How do I accomplish this?

AmrDeveloper
  • 3,826
  • 1
  • 21
  • 30

2 Answers2

0

You can calculate the file's length by using fseek to move to the end of the file, then ftell to read the current position (which is the same as the files length (in bytes)), and lastly use rewind to restore the file pointer to the head of the file:

fseek(fptr, 0, SEEK_END);
file_length = ftell(fptr);
rewind(fptr);

Once you know the file's length, you can dynamically allocate an array large enough to hold it. Here is a complete example:

FILE *fptr;
long str_length;
char *str;

// Open the file.
fptr = fopen(filename, "rb");

// Get the size of the file.
fseek(fptr, 0, SEEK_END);
str_length = ftell(fptr);
rewind(fptr);

// Allocate memory to contain the whole file including the null byte.
str = calloc(str_length + 1, sizeof(char)); // +1 for null byte.

// Read the contents of the file into the buffer.
fread(str, 1, str_length, fptr);

// Null terminate the string.
str[str_length] = '\0';

// Close the file.
fclose(fptr);

// Print the contents of the file.
printf("%s", str);

This example does not include error checking.

hgs3
  • 525
  • 3
  • 6
  • Please add a check for the return value for `fopen` – Ed Heal Feb 18 '21 at 21:45
  • 1
    *You can calculate the file's length by using `fseek` to move to the end of the file...* [Not portably](https://port70.net/~nsz/c/c11/n1570.html#note268): "Setting the file position indicator to end-of-file, as with `fseek(file, 0, SEEK_END)`, has undefined behavior for a binary stream..." [Also](https://port70.net/~nsz/c/c11/n1570.html#7.21.9.2p3): "A binary stream need not meaningfully support `fseek` calls with a `whence` value of `SEEK_END`." I'm betting whoever taught you to use `fseek()`/`ftell()` to get the size of a file left that out. – Andrew Henle Feb 18 '21 at 21:48
  • 1
    You could do `struct stat buf; long length = fstat(fileno(fptr,) &buf) == 0 ? buf.st_size : 0` – Ed Heal Feb 18 '21 at 21:55
  • @EdHeal You are correct, I am not checking return values, but `fopen` isn't the only function that should be checked. I intentionally omitted error checking (as noted in my answer) to keep it compact. – hgs3 Feb 18 '21 at 22:02
  • @AndrewHenle Yup, on POSIX you can use `stat` as @EdHeal suggested and on Windows use `GetFileSize`. – hgs3 Feb 18 '21 at 22:02
  • @hgs3 - At least add it to the comment `open file`...etc – Ed Heal Feb 18 '21 at 22:04
0

On a POSIX system, you can use getline:

FILE *fptr = fopen(filename,"r"); //Open the required file in read mode
for(i = 0; i < 3; i++) {
    char *str = 0;
    int len = 0;
    if (getline(&str, &len, fptr) > 0) {
        printf("%s", str);
        free(str); }
}
Chris Dodd
  • 119,907
  • 13
  • 134
  • 226