'I have a confusing C problem about writing files in reverse

It's my sloppy code that displays a text code in reverse. Idk why the code activates with i>=-1, not i>=0. fseek(fp,-1,SEEK_SET) and fseek(fp,0,SEEK_SET) should derive NULL and first letter of fp, not first letter and second letter of fp... Plus, I can't notice the difference between fseek(fp,-1,SEEK_CUR) and fseek(fp,i,SEEK_SET), but the latter one only activates. The former one only results the last letter of the file.

#include <stdio.h>
#include <string.h>
#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
int main(){
    FILE *fp=fopen("words.txt","r");
    fseek(fp,0,SEEK_END);
    int size=ftell(fp);
    char *buffer=malloc(sizeof(size+1)); //measuring length
    memset(buffer,0,size+1);
    for(int i=size;i>=-1;i--){ 
        fread(buffer,1,1,fp); 
        fseek(fp,i,SEEK_SET); //it doesn't work while fseek(fp,-1,SEEK_CUR);
        fwrite(buffer,sizeof(char),1,stdout);
    }
    fclose(fp);
    free(buffer);
}

words.txt

Hello, world!

result with i>=-1,i>=0.

!dlorw, olle //-1
!dlorw, olleH //0

result with fseek(fp,-1,SEEK_CUR), fseek(fp, i ,SEEK_SET)

!!!!!!!!!!!!! //when CUR(last letter*len of file)
!dlrow, olleH //when SET


Solution 1:[1]

There are several issues:

First of all

malloc(sizeof(size+1))

should be

malloc(size+1)

The sizeof operator gives you the size of its argument which is the size of an int on your platform (which is most likely 4 or 8).

But you don't need buffer anyway because you only read one char at a time, so a fixed buffer of size 1 is good enough.

Then your for loop is wrong. The very first fread will try reading beyond the end of the file because of the previous fseek(fp,0,SEEK_END).

This would be correct:

for (int i = size - 1; i >= -1; i--) {
  fseek(fp, i, SEEK_SET);
  fread(buffer, 1, 1, fp);
  fwrite(buffer, sizeof(char), 1, stdout);
}

Using fseek(fp, -1, SEEK_CUR) it's slightly more complicated:

fseek(fp, -1, SEEK_CUR);
for (int i = size -1; i > -1; i--) {
  fread(buffer, 1, 1, fp);
  fwrite(buffer, sizeof(char), 1, stdout);
  fseek(fp, -2, SEEK_CUR);  // you need -2 here for compensating
                            // the 1 char read with fread
}

But anyway the most efficient (and simplest) method to achieve what you want would be to read the whole file into buffer with a single fread and then simply display the charcacter in buffer from the end to the beginning. I leave this as an exercise for you.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1