subzero subzero - 4 years ago 69
C Question

Reading and writing to a file at the same time in C

Supposed to swap every two lines in a file until just one line remains or all lines are exhausted. I don't want to use another file in doing so.

Here's my code:

#include <stdio.h>

int main() {
FILE *fp = fopen("this.txt", "r+");
int i = 0;
char line1[100], line2[100];
fpos_t pos;
fgetpos(fp, &pos);

//to get the total line count
while (!feof(fp)) {
fgets(line1, 100, fp);
i++;
}

i /= 2; //no. of times to run the loop
rewind(fp);

while (i-- > 0) { //trying to use !feof(fp) condition to break the loop results in an infinite loop
fgets(line1, 100, fp);
fgets(line2, 100, fp);

fsetpos(fp, &pos);

fputs(line2, fp);
fputs(line1, fp);

fgetpos(fp, &pos);
}

fclose(fp);
return 0;
}


content in this.txt:

aaa
b
cc
ddd
ee
ffff
gg
hhhh
i
jj


content after running the program

b
aaa
ddd
cc
ddd
c
c

c


i
jj


I've even tried using
fseek
in place of
fgetpos
just to get the same wrong result.

From what I figured, after the second while loop has run two times (i.e the first four lines have been processed), the cursor is rightfully at 17th byte where it is supposed to be (as returned by the call to
ftell(fp)
)
and even the file contents after the 4th line are unchanged and somehow for some reason when
fgets
is called when the loop is running for the third time, the contents read into arrays line1 and line2 are "c\n" and "ddd\n" respectively.

AGAIN, I don't want to use another file to accomplish this, I just need to figure out what exactly is going wrong behind the screen

Any leads would be appreciated. Thank you.

Answer Source

There are multiple problems in your code:

  • You do not check if fopen() succeeds, risking undefined behavior.

  • The loop to determine the total number of lines is incorrect.
    Learn why here: Why is “while ( !feof (file) )” always wrong?

  • You do not actually need to compute the total number of lines.

  • You should call fflush() to write the contents back to the file before changing from writing back to reading.

The C Standard specifies this restriction for files open in update mode:

7.21.5.3 The fopen function

[...] output shall not be directly followed by input without an intervening call to the fflush function or to a file positioning function (fseek, fsetpos, or rewind), and input shall not be directly followed by output without an intervening call to a file positioning function, unless the input operation encounters end-of-file.

This explains why just reading the file position after writing the lines in reverse order causes problems. Calling fflush() should solve this issue.

Here is a corrected version:

#include <stdio.h>

int main(void) {
    FILE *fp;
    char line1[100], line2[100];
    fpos_t pos;

    fp = fopen("this.txt", "r+");
    if (fp == NULL) {
        fprintf(stderr, "cannot open this.txt\n");
        return 1;
    }

    while (fgetpos(fp, &pos) == 0 &&
           fgets(line1, sizeof line1, fp) != NULL &&
           fgets(line2, sizeof line2, fp) != NULL) {

        fsetpos(fp, &pos);
        fputs(line2, fp);
        fputs(line1, fp);
        fflush(fp);    
    }

    fclose(fp);
    return 0;
}
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download