Home > database >  character by character reading from a txt file, and writing to another file in C?
character by character reading from a txt file, and writing to another file in C?

Time:11-27

(C, visual studio 2022 environment)

I have to write a program that read a .txt file (character by character) and puts each character in another .txt file (in the same directory created by visual studio). the initial .txt file is too long, so in this question I wrote a smaller part of the data.

this is my initial file.txt:

3.456789 3.456789 3.5671234566 3.450934759435735738457 3.3298017238973289742398074238 3.456789 3.456789 3.5671234566 3.450934759435735738457 3.3298017238973289742398074238 3.456789 3.456789 3.5671234566 3.450934759435735738457 3.3298017238973289742398074238 3.456789 3.456789 3.5671234566 3.450934759435735738457 3.3298017238973289742398074238

and this is the code: (i used only the main.c because it's only a test to test the C input output):

the code is supposed to do these stuff:

  • open a read-only file. (pointed to by f).
  • (null pointer check. I checked f).
  • I defined the array with the name x. (it's a pointer that points to 0-th element of the array).
  • I defined CHAR COUNT because I used it in the first while loop (the read part).
  • (null pointer check. I checked x).
  • reading consists of an infinite loop made up by these 3 parts: read, check, use.

read part: I assigned to count the value of fgetc [fgetc() return value is a character]. fgetc takes characters of f stream.

check part: I checked if it's equal to EOF macro. if it's the case, then "break" and go outside the first while loop. {while writing this question, I'm thinking about one possible error in this phase: if this check condition holds true, than the second array is executed but I'd have another error in the second while loop because I didn't read the first file entirely}.

use part: If the if check holds false, than do a calloc and allocate enough memory (i, sizeof(double)) to store the value that is read with fgetc.

(another null pointer check. I checked x again because I have allocated x). {while writing this question, I'm thinking if calloc have to be checked or not, because it's not like malloc. malloc fills up allocated memory with random stuff, but calloc initializes the memory to zero}.

I assigned the values (x[i] = count).

I incremented i by 1, of course.

  • outside the first loop, I opened another file (pointed to by g), but this file is a write only file.
  • (null pointer check. I checked g).
  • second infinite while loop, but I used fputc (it writes one character on the file).
  • (EOF check. I checked whether or not x[j] is equal to EOF macro. -outside the second while loop, I freed allocated memory, and I closed the txt files. (before the return 0 statement).

to sum up my question:

  • "while writing this question, I'm thinking about one possible error in this phase: if this check condition holds true, than the second array is executed but I'd have another error in the second while loop because I didn't read the first file entirely" what do you think?

  • "while writing this question, I'm thinking if calloc have to be checked or not, because it's not like malloc. malloc fills up allocated memory with random stuff, but calloc initializes the memory to zero". what do you think?

and the general question: is it legit to write this program this way, or do you think there's a wiser way to do the same task? (note: I know that I could've used fprintf() and fscanf(), but I wanted to test my skills to write a program that performs the same task but characters by characters (on a long txt file)).

(I have two errors and three warnings:

1st error: uninitialized local variable f used (why? I have initialized it because it points to the beginning of the file)

2nd error: uninitialized local variables x used (why? x is a pointer and I have checked if it's a null pointer so I don't have to initialize it)

1st warning: "function": incompatible types (from "FILE *" to "const char *".

the remaining warnings are like the errors, the debugger copied it in the warning list too.

   #define _CRT_SECURE_NO_WARNINGS
    #include <stdio.h>
    #include <stdlib.h>
    int main(void) {
    
        FILE* f = fopen(f, "r"); 
        if (f == NULL) {
            return NULL; 
        }
        int* x; char count = 0; 
        if (x == NULL) {
            return NULL; 
        }
        unsigned int i = 1; 
        while (1) {
            count = fgetc(f); 
            if (count == EOF) {
                break; 
            }
             
            int* x = calloc(i, sizeof(double)); 
            if (x == NULL) {
                return -3; 
            }
            x[i] = count;
            i  ; 
        } 
        FILE* g = fopen("otherfile.txt", "w"); 
        if (g == NULL) {
            return -2; 
        }
        int j = 1; 
        while (1) {
            fputc(x[j], g); 
            if (x[j] == EOF) {
                break; 
            }
            j  ; 
        }
    
    
        free(x); 
        fclose(f); 
        fclose(g); 
        return 0; 
    }
        

CodePudding user response:

FILE* f = fopen(f, "r"); 

This is obvious typo. It should be fopen("inputfile", "r").

int* x; 
if (x == NULL) { return NULL;  }

x is not initialized. That means it could be NULL (zero) or it could be any other random value. You can't test it at this point.

while (1) {
    ...
    int* x = calloc(i, sizeof(double)); 
}

Here you have declared a different pointer with the same name. The second x is a different variable because it's in a different scope (when you put variables inside {} the scope changes)

The second x allocates memory then it is lost in the next iteration of the loop. This leads to significant memory leak.

sizeof(double) is not applicable. If you intend to store in a char buffer, first you have to know how many characters there are in the file. It's impossible to know that before you read the file.

To get around this problem, you can go through the file once and count the characters, or you can check the file size.

Once you allocate enough memory, you can use fread/fwrite to read the entire file.

int main(void)
{
    FILE* fin = fopen("input.txt", "r");
    if (!fin) { perror("input error"); return 0; }
    FILE* fout = fopen("output.txt", "w");
    if (!fout) { perror("fout error"); return 0; }

    fseek(fin, 0, SEEK_END); //go to the end of file
    size_t filesize = ftell(fin); //get file size
    fseek(fin, 0, SEEK_SET); //go back to the beginning 

    //allocate enough memory
    char* buffer = malloc(filesize * sizeof(char));

    //read one character at a time (or `fread` the whole file)
    size_t i = 0;
    while (1)
    {
        int c = fgetc(fin);
        if (c == EOF) break;

        //save to buffer
        buffer[i  ] = (char)c;
    }

    //write one character at a time (or `fwrite` the whole file)
    for (i = 0; i < filesize; i  )
        fputc(buffer[i], fout);

    free(buffer);
    fclose(fin);
    fclose(fout);
    return 0;
}
  • Related