Check if the next read will set EOF indicator - c

What's the best way to check if I've reached the end of a FILE* stream without manually keeping track of the current cursor position and file size? The implementation should work in read and read/write mode of fopen.
I came up with this:
int iseof(FILE *fp)
{
int ch = fgetc(fp);
if(ch == EOF) return 1;
ungetc(ch, fp);
return 0;
}
This does the trick but of course it has the overhead of reading a character and potentially pushing it back into the stream. That's why I was wondering whether there was a nicer solution. Just using feof() won't work because this will only return true if reading at or past the end of file has occurred.
Any ideas?

It is probably best to just do this check manually in a while loop than try to write a function to wrap it up:
ch = fgetc(fp);
while (ch != EOF) {]
// do something with ch
ch = fgetc(fp);
}

Related

How to best parse comments lines in a file with C

Okay so I'm trying to read in a PPM file (p3 format) and I want to read the comments (which are #s in ppm files).
The problem is that I don't know how to make C do what is in my head, heres what I want it to do.
read the file
where # appears, store all characters until the %\n character appears
repeat until all comments are read
I understand that I should be using some variations of getc, fgets and fscanf but I don't know how to apply them in this context.
I would put some code up showing what i've tried with getc, fgets and fscanf but to be brutally honest I have no idea how to use any of those functions and none of the info I can find seems to help and I really don't think any of my implementations are even doing anything.
Does anyone /is anyone willing to show me an example of how to parse a line with any of these functions?
Simple, two-state FSM, reading one character at a time:
#include <stdio.h>
int main(void)
{
int ch, state;
for(state=0;; ) {
ch = getc(stdin);
if (ch == EOF) break;
if (state) {
putc(ch, stdout);
if (ch == '\n') state=0;
continue;
}
if (ch == '#') state = 1;
}
return 0;
}
Using ./a.out <fsm.c
include <stdio.h>
') state = 1;

skip to next line of file ignoring content

hi so i have a program where if there is an # at the begining of the first line of the text file it needs to be ignored, how do you jump to the next line of file? ignoring all that there is after the #?
for example:
#1234
5
I want to print 5 and the rest to be ignored.
I only managed to skip the # if there is nothing behind it
while (a == '#' || a == '\r'|| a == '\n') {
fscanf(inp, "%c", &a);
}
As for your previous question, if your want to ignore comment lines with an initial #, it is highly recommended to read the file line by line with fgets() and to handle non comment lines directly while ignoring comment lines.
It is actually non trivial to do it with fscanf because depending on your format lines, the linefeed may or may not have been consumed.
If you are at the start of a line and want to read the next char while ignoring the comment lines, do this:
int c; // Must be int to accommodate for EOF.
while ((c = getc(inp)) == '#') {
while ((c = getc(inp)) != EOF && c != '\n')
continue;
}
// Here c contains the first char from a non comment line or EOF.
Instead of
while (a == '#' || a == '\r'|| a == '\n') {
fscanf(inp,"%c",&a);
}
Try (pseudo code):
If FirstChar == '#'
Loop/scan until '\n'
On nextline here
If you want to use fscanf().
If better performance is needed, work on buffers directly.

Printing the contents of a file using getc and putc

I've seen this question has been asked before, but none of the answers seemed to work for my problem.
I am attempting to write a function that will read the contents of a file, and print them. Here is my code;
int main()
{
int c;
fseek(stdin, 0, SEEK_SET);
c = getc(stdin);
while ((c = getchar()) != EOF)
{
putchar(c);
fseek(stdin, 1, SEEK_CUR);
c = getc(stdin);
}
}
When running the code, I pipe in a file using;
./[Program] < [File.txt]
eg.
./FileRead < Hello.txt
However, when I run it, I get a jumble of random letters. Here is an example:
The contents of the file I am piping in:
Hello World!
This is a test file.
I hope this works!
And here is the output:
eood
Tss sfe
Io iwk
Can anyone help me work out what is wrong?
Just to note that the getc() function moves the active file pointer to the next position automatically after reading a character, so the
//fseek(stdin, 0, SEEK_SET);
opens the file and sets the pointer at the first char
//c = getc(stdin);
The
//getc()
gets the next character in line the 'H' and moves
the pointer forward one character
c now == 'H'
while ((c = getchar()) != EOF)
The
//getchar()
seams to be working (not recommended)
when reading from a file try using
//getc(<filepointer>)
c now == 'e' and the filepointer is moved to the
first 'l'.
Then you have
//putchar(c)
which prints the 'e' character
//fseek(stdin, 1, SEEK_CUR);
Moves the *fp ahead one character to the second 'l'
Then you have
// c = getc(stdin);
Read the next character in line which is the second 'l',
move the *fp to the ' ' space, and repeat.
Basically change the code to this:
while ((ch = getch(stdin)) != EOF)
{
putchar(c);
}
The code should work fine.
Note: For streams opened in text mode, fseek and _fseeki64have limited use, because carriage return–linefeed translations can cause fseek and _fseeki64to produce unexpected results. The only fseek and _fseeki64operations guaranteed to work on streams opened in text mode are:
•Seeking with an offset of 0 relative to any of the origin values.
•Seeking from the beginning of the file with an offset value returned from a call to ftell when using fseekor _ftelli64when using_fseeki64.

Reading a text file up to a certain character

Here's my dilemma. I have a file, and wish to read in all characters up until the program hits a '#', and ignore everything on that line after the '#'. For example
0 4001232 0 #comment, discard
This is frustrating, as it feels like there is a very simple solution. Thanks!
FILE *f = fopen("file.txt", "r");
int c;
while ((c = getc(f)) != '#' && c != EOF)
putchar(c);
Read a line using fgets, read through this line till you get a '#' character.
Read an another line...
There are plenty of ways and examples of how to do it. Usually, the idea is to have a variable that holds the state (before #, after # , after \n etc.) and run in a while loop until EOF. an example you can see here it's a program to remove C comments, but the idea is the same.
filePointer = fopen("person.txt", "r");
do
{
read = fgetc(filePointer);
//stop when '#' read or when file ends
if (feof(filePointer) || read == '#')
{
break;
}
printf("%c", read);
} while (1);
fclose(filePointer);
also you better check if file opened succesfully
if (filePointer == NULL)
{
printf("person.txt file failed to open.");
}
else
{
file operations
}
The solution depends on how you are "reading" that.
I could, for example, just remove all of those comments with sed 's/#.*//' <infile >outfile in bash.
EDIT: However, if I was parsing it manually, I could simply (in my loop for parsing it) have
if(line[i]=='#') {
continue;
}
which would stop parsing that line by exiting the loop.

feof() in C file handling

I am reading a binary file byte-by-byte,i need determine that whether or not eof has reached.
feof() doesn't works as "eof is set only when a read request for non-existent byte is made". So, I can have my custom check_eof like:
if ( fread(&byte,sizeof(byte),1,fp) != 1) {
if(feof(fp))
return true;
}
return false;
But the problem is, in case when eof is not reached, my file pointer is moved a byte ahead.
So a solution might be to use ftell() and then fseek() to get it to correct position.
Another solution might be to buffer the byte ahead in some temporary storage.
Any better solutions?
If you're reading a byte at a time, the idiomatic way to do this is with fgetc:
int c;
while ((c = fgetc(fp)) != EOF) {
// Do something.
}
and then you shouldn't need to deal with feof.
I typically do something like this:
int get_next_char(FILE* fp, char *ch)
{
return fread(ch, sizeof(char),1, fp) == 1;
}
// main loop
char ch;
while (get_next_char(fp, &ch))
process_char(ch);
if (!feof(fp))
handle_unexpected_input_error(fp);
It's best to structure your code so that you try to read some data and if the read does not succeed due to reaching the end-of-file, you deal with it there (i.e. see Kristopher Johnson's answer).
If you absolutely hate this, you can use ungetc to return a single character back to the stream and it will be available in the next read call:
int c = fgetc(fp);
if (c == EOF)
{
// handle eof / error
}
else
{
ungetc(c, fp);
// the next read call is guaranteed to return at least one byte
}
I'm not clear, but if you're interested in knowing before you read the byte if EOF has been reached, put your feof() test before the fread() rather than after it.
actually, if I read correctly, you don't even want to do the fread so:
return feof(fp) ? true : false;
I would suggest using:
fseek(myFile, 0, SEEK_END);
fileLen = ftell(myFile);
fseek(myfile, 0, SEEK_SET);
When you first open the file to determine the length. Then set up your read-loop to never read off the end. You can use ftell to figure out where you are, and compare to fileLen to figure out how much further you have to go.

Resources