4

I use below code to read a char from file and replace it with another, but I have an error.loop in going to end of file.

What is wrong?

I tested this code on linux (netbeans IDE) and it was correct and worked beautiful but when I tried to use VS 2008 in windows , I found a non end loop.

//address = test.txt

FILE *fp;
fp=fopen(address,"r+");
if(fp == 0)
{
    printf("can not find!!");
}
else
{
    char w = '0';  /// EDIT : int w;
    while(1)
    {
        if((w = fgetc(fp)) != EOF)
        {
            if((w = fgetc(fp)) != EOF)
            {
                fseek(fp,-2,SEEK_CUR);
                fprintf(fp,"0");
            }
        }
        else
        {
            break;
        }
    }
} 
fclose(fp);

2 Answers2

6

You are storing the result of fgetc in a char, instead of an int.

char w = '0'; /* Wrong, should be int. */

Incidentally, this problem is mentioned in the C FAQ.

If type char is unsigned, an actual EOF value will be truncated (by having its higher-order bits discarded, probably resulting in 255 or 0xff) and will not be recognized as EOF, resulting in effectively infinite input.

EDIT

Reading your question again, it's highly fishy the way you seek back two characters and write one character. That could well lead to an infinite loop.

EDIT2

You (likely) want something like this (untested):

while ((w = getc(fp)) != EOF) {
    fseek(fp, -1, SEEK_CUR);
    fprintf(fp, "0");
    fflush(fp); /* Apparently necessary, see the answer of David Grayson. */
}
cnicutar
  • 178,505
  • 25
  • 365
  • 392
  • yes you are correct...it is the problem.but what is solution? –  Jul 09 '11 at 08:27
  • 1
    i tested your edit2 and in this i have a non end loop , and when i break with ctrl+c and then open file with notepad i see milions of zero –  Jul 09 '11 at 08:41
  • @mimad You have to replace **your entire while** with that I posted. – cnicutar Jul 09 '11 at 08:42
  • yes ... i did it,,,,know the code is like below but does not work yet! FILE *fp; fp = fopen(address,"r+"); if(fp == 0) { printf("can not find!!"); } else { int w = '0'; while ((w = getc(fp)) != EOF) { fseek(fp, -1, SEEK_CUR); fprintf(fp, "0"); } fclose(fp); } –  Jul 09 '11 at 08:43
  • 1
    When switching between write and read you might need another fseek. – Bo Persson Jul 09 '11 at 08:48
  • @Bo Persson You are right. You need an `fflush` or `fseek`. See my answer. – David Grayson Jul 09 '11 at 08:56
  • EOF is defined to be -1 (at least in my environment) and a `char` can represent -1, so changing the `char` to an `int` should not affect the behavior of this program, assuming there are no -1 (0xFF) bytes in the input file. See my answer for the real problem. – David Grayson Jul 09 '11 at 08:59
  • @David Grayson While this too is a problem, the char is a real issue :-) See the C FAQ. – cnicutar Jul 09 '11 at 09:02
  • Sure, it's real issue, but it wasn't causing the infinite loop, assuming the input file was ASCII and `char` is signed in the OP's compiler. The C FAQ says: "The bug can go undetected for a long time, however, if chars are *signed* and if the input is all *7-bit characters*." – David Grayson Jul 09 '11 at 09:05
  • 1
    @David Grayson Fine :-) I myself don't like assuming much. – cnicutar Jul 09 '11 at 09:10
3

The fopen documentation on cplusplus.com says:

For the modes where both read and writing (or appending) are allowed (those which include a "+" sign), the stream should be flushed (fflush) or repositioned (fseek, fsetpos, rewind) between either a reading operation followed by a writing operation or a writing operation followed by a reading operation.

We can add an fflush call after the fprintf to satisfy that requirement.

Here is my working code. It creates a file named example.txt and after the program exits that file's contents will be 000000000000n.

#include <stdio.h>

int main(int argc, char **argv)
{
    FILE * fp;
    int w;

    fp = fopen("example.txt","w");
    fprintf(fp, "David Grayson");
    fclose(fp);

    fp = fopen("example.txt","r+");
    while(1)
    {
        if((w = fgetc(fp)) != EOF)
        {
            if((w = fgetc(fp)) != EOF)
            {
                fseek(fp,-2,SEEK_CUR);
                fprintf(fp,"0");
                fflush(fp);  // Necessary!
            }
        }
        else
        {
            break;
        }
    }
    fclose(fp);
}

This was tested with MinGW in Windows.

David Grayson
  • 84,103
  • 24
  • 152
  • 189