How to Read from a Text File, Character by Character in C++

Reading a file character by character in C

There are a number of things wrong with your code:

char *readFile(char *fileName)
{
FILE *file;
char *code = malloc(1000 * sizeof(char));
file = fopen(fileName, "r");
do
{
*code++ = (char)fgetc(file);

} while(*code != EOF);
return code;
}
  1. What if the file is greater than 1,000 bytes?
  2. You are increasing code each time you read a character, and you return code back to the caller (even though it is no longer pointing at the first byte of the memory block as it was returned by malloc).
  3. You are casting the result of fgetc(file) to char. You need to check for EOF before casting the result to char.

It is important to maintain the original pointer returned by malloc so that you can free it later. If we disregard the file size, we can achieve this still with the following:

char *readFile(char *fileName)
{
FILE *file = fopen(fileName, "r");
char *code;
size_t n = 0;
int c;

if (file == NULL)
return NULL; //could not open file

code = malloc(1000);

while ((c = fgetc(file)) != EOF)
{
code[n++] = (char) c;
}

// don't forget to terminate with the null character
code[n] = '\0';

return code;
}

There are various system calls that will give you the size of a file; a common one is stat.

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

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;
}

Reading file character-by-character and comparing those characters in C

You can do this with one bool variable, say boolean newLine = false;, initialized to false. That will be indicator that let you know if last character was A.

 boolean newLine = false;
FILE *fp;
int c;

fp = fopen("datafile.txt", "w");

while((c = fgetc(fp)) != EOF) {
if (newLine) {
// Here you put char in new line
if (c == 'A'){
newLine = true;
}
else {
newLine = false;
}
}
}

fclose(fp);

character by character reading from a file in C

To just do what you asked for, you would have to read the whole file again:

...
// go back to the beginning
fseek(text, 0L, SEEK_SET);
// read
ssize_t readsize = fread(Str, sizeof(char), count, text);
if(readsize != count) {
printf("woops - something bad happened\n");
}

// do stuff with it
// ...

fclose(text);

But your string is not null terminated this way. That will get you in some trouble if you try to use some common string functions like strlen.

To properly null terminate your string you would have to allocate space for one additional character and set that last one to '\0':

...
// allocate count + 1 (for the null terminator)
Str = (char*)malloc((count + 1) * sizeof(char));

// go back to the beginning
fseek(text, 0L, SEEK_SET);
// read
ssize_t readsize = fread(Str, sizeof(char), count, text);
if(readsize != count) {
printf("woops - something bad happened\n");
}
// add null terminator
Str[count] = '\0';

// do stuff with it
// ...

fclose(text);

Now if you want know the number of characters in the file without counting them one by one, you could get that number in a more efficient way:

...
text = fopen("text.txt", "r");

// seek to the end of the file
fseek(text, 0L, SEEK_END);
// get your current position in that file
count = ftell(text)

// allocate count + 1 (for the null terminator)
Str = (char*)malloc((count + 1) * sizeof(char));
...

Now bring this in a more structured form:

// open file
FILE *text = fopen("text.txt", "r");

// seek to the end of the file
fseek(text, 0L, SEEK_END);
// get your current position in that file
ssize_t count = ftell(text)

// allocate count + 1 (for the null terminator)
char* Str = (char*)malloc((count + 1) * sizeof(char));

// go back to the beginning
fseek(text, 0L, SEEK_SET);
// read
ssize_t readsize = fread(Str, sizeof(char), count, text);
if(readsize != count) {
printf("woops - something bad happened\n");
}

fclose(text);

// add null terminator
Str[count] = '\0';

// do stuff with it
// ...

Edit:

As Andrew Henle pointed out not every FILE stream is seekable and you can't even rely on being able to read the file again (or that the file has the same length/content when reading it again). Even though this is the accepted answer, if you don't know in advance what kind of file stream you're dealing with, his solution is definitely the way to go.

c function to read character by character from a txt file, make it into int and store it in a linked list

digit_ = fgetc("fptr")

It's totally wrong. The declaration of fgetc function:

 int fgetc(FILE *stream);

So, if you want to read the context of the file, you have to open it first:

FILE * fptr = fopen("filename", "r"); // filename: input.txt for example.
if(!fptr) {
// handle the error.
}

// now, you can read the digits from the file.
int c = fgetc(fp);

If your file contents only the digits (from 0 to 9), you can use fgetc to read digit by digit.
The peusedo-code:

    FILE * fptr = fopen("input.txt", "r");
if(!fptr) {
// handle the error.
}
while(1) {
int c = fgetc(fp);
if(isdigit(c)) {
int digit = c-'0';
// add "digit" to linked list
} else if (c == '\n') { // quit the loop if you meet the enter character
printf("end of line\n");
break;
} else if(c == ' ') { // this line is optional
printf("space character\n");
}
}

// print the linked list.

For inserting or printing the linked list, you can search in google. There will be a ton of examples for you. For example, example of inserting and printing linked-list

Reading file character by character, line by line in C

Obviously I can't use your exact code, or you would not have asked the question, but this is a similar idea, done a bit differently, and also using the fgets which was causing you trouble. It works by searching each line for digits, and non-digits. Note that I have #define MAXLEN 2000 to be generous, because in the previous question, you say each number can have 500 digits, so the line might be at least 1000 characters.

#include <stdio.h>
#include <ctype.h>

#define MAXLEN 2000

int main(void)
{
FILE *fp;
char line[MAXLEN];
char *ptr;
if((fp = fopen("test.txt", "rt")) == NULL)
return 0; // or other action

while(fgets(line, MAXLEN, fp) != NULL) {
ptr = line;
// first number
while(*ptr && !isdigit(*ptr)) { // skip non-digits
ptr++;
}
while(*ptr && isdigit(*ptr)) {
printf("%c", *ptr++); // print digits
}
printf(" ");

// second number
while(*ptr && !isdigit(*ptr)) { // skip non-digits
ptr++;
}
while(*ptr && isdigit(*ptr)) {
printf("%c", *ptr++); // print digits
}
printf("\n");

}
fclose(fp);
return 0;
}

EDIT you could make it more concise like this, with a loop to read each set of digits:

char *terminate = " \n";                    // 1st number ends with space, 2nd with newline
int i;
while(fgets(line, MAXLEN, fp) != NULL) {
ptr = line;
for(i=0; i<2; i++) {
while(*ptr && !isdigit(*ptr)) { // skip non-digits
ptr++;
}
while(*ptr && isdigit(*ptr)) {
printf("%c", *ptr++); // print digits
}
printf("%c", terminate[i]); // space or newline
}
}

Program output (from your input):

10 5003
20 320
4003 200


Related Topics



Leave a reply



Submit