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;
}
- What if the file is greater than 1,000 bytes?
- You are increasing
code
each time you read a character, and you returncode
back to the caller (even though it is no longer pointing at the first byte of the memory block as it was returned bymalloc
). - You are casting the result of
fgetc(file)
tochar
. You need to check forEOF
before casting the result tochar
.
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
On How to Recognize Rvalue or Lvalue Reference and If-It-Has-A-Name Rule
Setjmp/Longjmp: Why Is This Throwing a Segfault
How to Ensure That the Template Parameter Is a Subtype of a Desired Type
How-To Write a Password-Safe Class
Can Raw Pointers Be Used Instead of Iterators with Stl Algorithms for Containers with Linear Storage
Checking for Underflow/Overflow in C++
C++ Warning: Address of Local Variable
Using Maven for C/C++ Projects
Profiler for Visual Studio 2008, C++
Maximum Stack Size for C/C+ Program
Detect Gcc Compile-Time Flags of a Binary
Disable Eclipse's Error Discovery. (Codan False Positives)
What's the Difference Between a Const Member Function and a Non-Const Member Function
Convert String with Explicit Escape Sequence into Relative Character