1

I need to make a C program that removes empty lines as homework since we didn't study a way to removing characters from files my first attempt was to overwrite all the characters but both fprintf and fputc inserts characters.

#include <stdio.h>

#define MAX_SIZE 1000

int main() {
    FILE *fp = fopen("sortie.txt", "r+");
    int off = 0;
    for (char c1 = '\n', c2;;) {
        if (((c2 = fgetc(fp)) == '\n') && (c1 == '\n')) {
            off++;
            continue;
        }
        if (c2 == EOF) {
            fseek(fp, -off ,SEEK_CUR);
            fputc(EOF, fp);
            break;
        }
        //if(!off)continue;

        fseek(fp, -off, SEEK_CUR);
        fprintf(fp, "%c", c1 = c2);

        fseek(fp, off, SEEK_CUR);
    }
    fclose(fp);

    return 0;
}

second attempt was to replace them with '\0'

#include <stdio.h>

int main() {
    FILE *fp = fopen("sortie.txt", "r+");
    for (char c1 = '\n', c2;;) {
        if (((c2 = fgetc(fp)) == '\n') && (c1 == '\n')) {
            fseek(fp, -1, SEEK_CUR);
            fputc('\0', fp);
            fseek(fp, 1, SEEK_CUR);
        }
    }
    fclose(fp);

    return 0;
}

none worked

overwriting characters and replacing with 0

17
  • 2
    The way forwards is to create a new file. Although it is possible to overwrite single characters, this isn't the way to remove an empty line. A 0 has no place it a text file. Another good reason to create another file, is if things go wrong part way, you are likely to trash the file you are attempting to modifiy. Commented Feb 25, 2023 at 17:08
  • how do i replace single characters @WeatherVane Commented Feb 25, 2023 at 17:47
  • As weather vane says, do not edit the file. As a very good general rule, treat files as immutable. Life is better in so many ways if you do that. Files get written once, and then they never change. Instead, create a new file and rename it when you are done. It is much simpler to code and results in a more robust process. Commented Feb 25, 2023 at 17:47
  • i didnt want to create a new file because we didnt study it in class and this is for homework so not very serious but thanks for pointing it out Commented Feb 25, 2023 at 17:49
  • Please note that fgetc returns an int. Which is rather important for that comparison against the int value EOF. Commented Feb 25, 2023 at 17:51

1 Answer 1

0

In order to remove characters from a file, the length of the file must be reduced. There is no portable way to truncate a file, except to a size of 0.

A portable way to achieve your goal is to read the file contents in memory, perform whatever processing in memory and write back the new contents into a newly created file with the same name.

Here is an example with error checking:

#include <stdlib.h>

int main(void) {
    FILE *fp = fopen("sortie.txt", "r");
    if (fp == NULL) {
        perror("cannot open sortie.txt for reading");
        return 1;
    }
    char *buffer = NULL;
    size_t length = 0, size = 0;
    int c, last = '\n';
    while ((c = getc(fp)) != EOF) {
        if (c != '\n' || last != '\n') {
            if (length >= size) {
                size_t new_size = size + size / 2 + 32;
                char *new_buffer = realloc(buffer, new_size);
                if (new_buffer == NULL) {
                    perror("cannot reallocate buffer");
                    free(buffer);
                    fclose(fp);
                    return 1;
                }
                buffer = new_buffer;
                size = new_size;
            }
            buffer[length++] = (char)c;
        }
        last = c;
    }
    fclose(fp);
    fp = fopen("sortie.txt", "w");
    if (fp == NULL) {
        perror("cannot open sortie.txt for writing");
        free(buffer);
        return 1;
    }
    int status = 0;
    size_t written = fwrite(buffer, 1, length, fp);
    free(buffer);
    if (written != length) {
        fprintf(stderr, "error writing to sortie.txt: %zu written, expected %zu\n",
                written, length);
        status = 1;
    }
    if (fclose(fp)) {
        perror("error closing sortie.txt");
        status = 1;
    }
    return status;
}

The problem with this approach is the potential data loss if the program is interrupted at the wrong time before the updated contents is fully written.

For an alternative, more classic approach, which may handle files too large to fit in memory, you can write the modified contents to a new file, once this process is complete, you can remove the original file and rename the new file to the original name.

Here is an example of this latter approach:

#include <stdio.h>

int main(void) {
    FILE *fp = fopen("sortie.txt", "r");
    if (fp == NULL) {
        perror("cannot open sortie.txt");
        return 1;
    }
    FILE *f2 = fopen("sortie-new.txt", "w");
    if (fp2 == NULL) {
        perror("cannot open sortie-new.txt");
        return 1;
    }
    int c, last = '\n';
    while ((c = getc(fp)) != EOF) { 
        if (c != '\n' || last != '\n')
            putc(c, fp2);
        last = c;
    }
    fclose(fp);
    if (fclose(fp2)) {
        perror("error writing to sortie-new.txt");
        remove("sortie-new.txt");
        return 1;
    }
    if (remove("sortie.txt")) {
        perror("cannot remove sortie.txt");
        return 1;
    }
    if (rename("sortie-new.txt", "sortie.txt")) {
        perror("cannot rename sortie-new.txt");
        return 1;
    }
    return 0;
}
Sign up to request clarification or add additional context in comments.

4 Comments

actually saw this idea when searching google but i preferred not to go for it because it needs double the space plus we didnt see deleting and renaming files in class but thanks anyway
In actual practice, this will almost certainly not "use double the space". Even if you use the fopen/fwrite/fclose family, chances are good the files will never hit the physical disk and will just stay in the virtual file system the entire time. (If the files are big enough that this is actually a concern, you have a more difficult problem, and the solution to that problem is probably going to involve using disk to keep two copies of the files instead of trying to keep it all in memory, so you are back to this approach anyway.)
@WilliamPursell any way we didnt see in class the way to delete and rename files so i thought i shouldnt use them but i might use it as a last resort and hope the teacher doesnt read the code
@YellowFlash: if have not seen file deletion and such, then read the file in memory, which may require realloc if there is no maximum size and write back to the same file open with "w". If the teacher insists on using "r+", you should be careful and consider attending a different class.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.