Search code examples
cfilecommand-lineio

How to swap characters in a file specified (file name and characters) in the command line?


I'm learning about file commands and trying to write some programs. I want to specify two characters in command line, where the second one will replace the first one, every time the first character is found. The command line input would be [program_name].exe [file].txt [old_char] [new_char]. I came across this thread which had the same problem and I tried to fix my code by looking at the answer, but it creates an infinite loop.

int main(int argc, char *argv[])
{
    FILE *fp;
    char *string = {"Hellx"};
    char c;
    if ((fp = fopen(argv[1], "w")) != NULL)
    {
        fputs(string, fp);
        printf("Successfully written.\n");
        fclose(fp);

        if ((fp = fopen(argv[1], "r+")) != NULL)
        {
            while ((c = fgetc(fp)) != EOF)
            {
                if (c == *argv[2])
                {
                    fseek(fp, ftell(fp) - 1, SEEK_SET);
                    fprintf(fp, "%c", *argv[3]);
                    printf("Successfully changed.\n");
                }
            }
            fclose(fp);
        }
        else
            printf("Error on opening!");
    }
    else
        printf("Error on writing!");
    return 0;
}

So the output for this would be: Helloelloelloelloelloelloello..., while it should just change x to o. What's the problem with this code?


Solution

  • The man page for fopen(), in the section which discusses file opening modes, says

    When the "r+", "w+", or "a+" access type is specified, both reading and writing are enabled (the file is said to be open for "update"). However, when you switch from reading to writing, the input operation must encounter an EOF marker. If there is no EOF, you must use an intervening call to a file positioning function. The file positioning functions are fsetpos, fseek, and rewind. When you switch from writing to reading, you must use an intervening call to either fflush or to a file positioning function.

    (my bolding)

    So I suggest adding

    fflush(fp);
    

    after the fprintf() statement, as no repositioning is needed.


    As mentioned, you also should change the type to

    int c;
    

    so that EOF -1 can be distinguished from data 0xFF.