I'm writing my own shell in C and I need to detect EOF (for when I run ./myshell < commands.txt)
commands.txt contains:
ls
pwd
These both run fine separately from within the program. But when I run it with the text file, I get an infinite loop.
In my while(1) loop for the shell, the first thing I do is this:
if (feof(stdin)) { my_exit(); }
my_exit is simply:
void my_exit() {
printf("End of file! Bye\n");
exit(0);
}
Doesn't exit(0) end the program (and the loop)? Why am I getting
End of File! ByeEnd of File! ByeEnd of File! ByeEnd of File! ByeEnd of File! ByeEnd of File! Bye.... etc
I have also tried doing the fgets == NULL way. Same loop
The problem is that feof() tells you if the LAST input operation ran into EOF. But you're not checking this until the next iteration. So when you're at EOF, you do fgets() and then try to use the empty result that it returned.
What's happening is that you fork() a child process, and then call execvp() with an empty command name. This is failing, so the child process returns to the beginning of the loop, and does the same thing. Meanwhile, the parent process calls my_exit(). So each child process forks another child of its own, and then exits.
The way feof works is that it returns false as long as no read has hit EOF. feof by itself does not check the stream, but checks if EOF indicator has been set, which happens when something like fgets fails.
It really is not a very good practice to use feof in the control loop.
An example of validating EOF can be this:
while( fgets(line, sizeof(line), fp) != NULL )
fputs(line, stdout);
You can try like this...
int a=1;
while(a)
{
if (feof(stdin)) {
a = 0;
}
}
printf("End of file! Bye\n");
exit(0);
Related
I have a program x, which I want to cleanly terminate.
You can run it by simply doing ./x and use the terminal to write lines to stdin directly and terminate it by writing exit.
However, if you use: cat file.txt | ./x, the stdin is now piped from the file and therefore you can never type exit.
The best way to end this program would be for it to automatically terminate once the last line was read from the file.
Alternatively, I'd like to re-route stdin back to the terminal if that is at all possible, to further allow manual input as before.
Here is some sample code:
int main() {
// ...
while (ongoing) {
size_t n = 0;
char* ln = NULL;
getline(&ln, &n, stdin);
strtok(ln, "\n");
strtok(ln, "\r");
if (strcmp("exit", ln) == 0) {
break;
}
//...
}
}
you're using getline to read your input. getline returns -1 on EOF. This makes it easy.
if (-1==getline(...))
break;
When you have read all the input from a pipe, EOF will be raised up to indicate that the full input has been reached.
In your example, this will be rougly equivalent with exit, so you can also check the return value of getline to see if the EOF has reached (in which case -1 will be returned).
fwrite(&studentg,sizeof(studentg),1,p);
while(!feof(p))
{
printf("flag");
fread(&studentg,sizeof(studentg),1,p);
printf("%s\t%s\t%s\t%s\t%s\t%s\t\n",studentg.name,studentg.add,studentg.tel,studentg.pc,studentg.qq,studentg.email);
}
Why I put only one object in file,but it output two same line?
And if I put two objects in file,it output one object correct,but another repeated.
I try show feof(p)'s return value,it show me that after fread ,feof(p)'s return value is still 0.Can anyone explain how it happens?
You won't get an end of file until you try to read beyond the file. This means that you have to check eof before the print:
fwrite(&studentg,sizeof(studentg),1,p);
finish = 0;
while(!finish)
{
printf("flag");
fread(&studentg,sizeof(studentg),1,p);
finish = feof(p);
if (!finish)
{
printf("%s\t%s\t%s\t%s\t%s\t%s\t\n",studentg.name,studentg.add,studentg.tel,studentg.pc,studentg.qq,studentg.email);
}
}
or
fwrite(&studentg,sizeof(studentg),1,p);
while(1)
{
printf("flag");
fread(&studentg,sizeof(studentg),1,p);
if (feof(p)) break;
printf("%s\t%s\t%s\t%s\t%s\t%s\t\n",studentg.name,studentg.add,studentg.tel,studentg.pc,studentg.qq,studentg.email);
}
From http://www.cplusplus.com/reference/cstdio/feof/:
"This indicator is generally set by a previous operation on the stream that attempted to read at or past the end-of-file."
This means that end of file is usually detected after an operation.
To fix your code, you may for example replace the condition in while loop with 1 or true and break execution when eof is reached (run feof inside loop).
Use of feof is one of the biggest misconception among beginners in File I/O. Everybody at some point has done the same mistake once or twice.
The way you have used it is Pascal's way but C way is different. The difference is::
Pascal's function returns true if the next read will fail because of end of file.
C's function returns true if the last function failed.
Thats why your code prints the last line twice because after the last line is read in and printed out, feof() will still return 0 (false) and the loop will continue. The next fgets() fails and so the line variable holding the contents of the last line is not changed and is printed out again. After this, feof() will return true (since fgets() failed) and the loop ends.
The correct way to use it is::
while( 1 ) {
fgets(line, sizeof(line), fp);
if ( feof(fp) ) /* check for EOF right after fgets() */
break;
fputs(line, stdout);
}
Still better way::
while( fgets(line, sizeof(line), fp) != NULL )
fputs(line, stdout);
First of all you should include a complete, reproducing, example to what you want to do, not a combined fragment of the code, which is hard to reproduce. Otherwise, note that using fwrite()/fread() on struct contents directly is not portable (see the free online book Porting UNIX Software), and is prone to errors. But you didn't provide enough context for us to understand what went wrong.
This question already has answers here:
Why is “while( !feof(file) )” always wrong?
(5 answers)
Closed 9 years ago.
I have a problem using the function feof, this is my code:
while(!feof(archlog))
{ if(!fgets(line,MAXLINE,archlog))
printf("\nERROR: Can't read on: %s\n", ARCHTXT);
else
printf("%s",line);
}
When I run this, it prints the text of the file but makes an extra loop and prints the ERROR, I want to avoid this, I want it to only print the text of the file without the extra loop.
The loop will enter once more if the file ends with a new line.
A warkaround whould be:
while(!feof(archlog))
{ if(!fgets(line,MAXLINE,archlog))
printf("\nERROR: Can't read on: %s\n", ARCHTXT);
else
printf("%s",line);
if ( (c=fgetc(archlog)) == EOF)
break;
ungetc(c, archlog);
}
The EOF flag is set once your gets function reads the EOF. This means that the last iteration will always trigger the error message. After this, the loop tests for the EOF flag again, which was triggered on the last read and thus exits the loop.
You could get around this by placing the EOF test inside the loop. There you can either print the text on a successful read or set a boolean to exit the loop if there is a failure.
I always reverse the two function calls:
while(fgets(line,MAXLINE,archlog))
{ if(feof(archlog))
break;
else
printf("%s",line);
}
That gets me out when the end of file is read. Sometimes I 'or' in ferror(archlog) to the feof() call, to break out on error or EOF.
You should not use feof(FILE *f) in your loops as it returns true only if EOF is read, not reached, see How to use feof(FILE *f)?
Instead use fgets and its return code for the condition:
while(fgets(line, MAXLINE, archlog) != NULL) {
printf("%s", line);
}
There is no need for checking feof(archlog) inside the loop. For error checking use ferror(archlog).
why when using fscanf to acquire data from a file, is used 2 times, once before the "!feof(fin)" and later, as shown in the code below:
fscanf(fin, "%s", letta);
while(!feof(fin)){
fscanf(fin, "%s", letta);
}
the word read is not the same?
No the word read would not be the same since you read from the file twice, you would get different data each time.
The condition in the while tests to see if you are at the end of file, in order to do that a read attempt must have been made, which requires the fscanf() before the loop.
Once you are inside the loop you want to continue reading from the file. Presumably there would be more code inside the loop to process the data you are reading.
In the code you have posted, if you encountered the end of file with your first read attempt, you wouldn't enter the (while) loop.
Contrast this with a do-while construct where the test is at the bottom of the loop (ie the read occurs only once, at the "bottom" of the loop). There you will always enter the loop at least once.
There's probably no point in using feof() like this here, yet many people who are (I guess, apologies if I'm mistaken) learning C seem to "want to".
The fact is that fscanf() itself has a return value; if the file ends it will fail to do the requested scanning, and it will tell you so. It will even return the special constant EOF if the file ends. So just loop on the return value of fscanf():
while( fscanf(fin, "%s", letta) == 1 )
{
/* Process, parse, store or do whatever with letta. */
}
Because the EOF flag is only set after a call to fscanf. The condition while(!feof(fin)) doesn't make sense when fscanf hasn't been called yet.
feof doesn't return true until after you try to read past the end of file. Imagine a file like the following:
This is a test$
^
where ^ indicates the current location in the file and $ represents EOF. After the first call to fscanf(fin, "%s", letta);, the stream looks like this:
This is a test$
^
After three iterations of the loop (reading "is", "a", and "test"), you have this:
This is a test$
^
At this point, feof(fin) still returns false, because at this point all you know is that you've reached the end of the string "test". So your loop will execute one more time. Since you're at the end of the file, there's nothing to read, so the contents of letta will not be changed, so it will look like you've read "test" twice. Now feof(fin) will return true.
The moral of the story is that you should not use feof as your loop condition; rather, you should use the result of the read operation itself, like so:
errno = 0;
while (fscanf(fin, "%s", letta) == 1)
{
// process letta
}
if (feof(fin))
{
printf("Reached end of file\n");
}
else
{
perror("Error on read");
}
I am trying to get a basic understanding on how to use fputc in C. I have read some documentation that is out there and believed I had it right. But every time I try to use the script I wrote by executing ./fputc > test.txt where text.txt is a text file with one line of text.
This is my script:
int
main(int argc, char **argv){
int ch;
FILE *input;
input = fopen("text.txt", "w+");
while ((ch = getchar()) != EOF){
fputc(ch, input);
}
fclose(input);
return 0;
}
I get no errors on compilation and for some reason the script does not reach EOF at the end of the text file. Shouldn't the getchar return EOF when it reached the end of the text file?
The text (text.txt) file does not appear to be edited, although it is created. So somewhere in my while loop something is going wrong.
I am new to C programming (if you couldn't tell) and this little script has me befuddled.
Any help would be appreciated, or any links to sites with further detail would also be great.
Cheers,
S.
What you in essence say is:
Console: Run my_program and write anything it outputs to test.txt.
Program: Open text.txt and write any input to stdin to that file.
Your console normally have three standard streams stdin, stdout and stderr. These streams you can redirect. If you are on Windows also look at i.e. redirection.
When you say ./my_prog > test.txt, what you tell your console, (not my_prog), is to write anything my_prog writes to stdout to the file test.txt.
If you in your code say i.e. printf("Hello");, then Hello would be written to the file test.txt.
If you had turned your redirection around by saying ./my_prog < test.txt instead, would be; stream the file test.txt to my_prog. Which, in turn, if there was any text in test.txt would result in a copy of test.txt to text.txt.
Now in your code you say:
int main(void)
{
int ch;
FILE *input;
/* Here you open a handle to the file text.txt for reading and writing */
input = fopen("text.txt", "w+");
while ((ch = getchar()) != EOF) { /* get next char from stdin */
fputc(ch, input); /* write that char to the handle input */
}
fclose(input); /* close the handle */
return 0;
}
So what happens, the way you run it, is:
In your code:
Open text.txt
Wait for input (data entered to stdin) - typically user entering text to console, passed to program when Enter is pressed.
In console:
Redirect anything from my_prog to test.txt.
You say:
the script does not reach EOF
Well, as it reads from stdin it will only (not without exception) get EOF under two conditions.
If you redirect a file to your program. I.e. ./my_prog < foo.txt (notice <, not >).
- What would happen then is that my_prog would read the data from the file foo.txt and when that file ends your program would receive a EOF. And, hence quit.
If you manually enter EOF to stdin.
- On Linux and OSX Ctrl-D, on Windows Ctrl-Z
Now, if you test this by typing text to console remember that write actions like fputc()is buffered. What this mean is that the data is not written to the file right away, but only when a given amount of data is in buffer, fflush() is called, stream is closed, you turn off buffering, etc.
Also; if you run your program. Enter text, enter some more text, and then hit Ctrl-C to abort the program it is a big chance you end with no data in your text.txt.
The reason for this is that the program is killed and thereby fclose() never called, and hence no flush to file.
On your further endeavors in programming it would be a very good idea to make a habit of not presuming anything. I.e. do not presume fopen() is OK.
FILE *fh;
char *outfile = "foo.txt";
if ((fh = fopen(outfile, "w")) == NULL) {
fprintf(stderr,
"Unable to open file %s\n --",
outfile);
perror(" fopen() ");
return 1;
}
Most functions has a way to check if operation was a success. I.e:
if (fputc(ch, fh) != ch) { err ...
This will make your code a lot safer, give you hints on where it fails etc.
Some links:
Look at redirection links at top of post.
Look at the functions in stdio.h (good overview), stdio.h (examples etc.). I.e.:
stdin
stdout
stderr
fopen()
fflush()
setvbuf()
setbuf()
...
getchar returns the next character from the standard input (stdin).
It is equivalent to getc with stdin as its argument.
Hence, your code reads from standard input instead of FILE* input.
Use fgetc here.
fgetc returns the character currently pointed by the internal file position indicator of the specified stream. The internal file position indicator is then advanced by one character to point to the next character.
So, Use fgetc to read from a file:
while ((ch = fgetc(input)) != EOF)
your program and the shell are both writing the same file. you should remove the output redirection > test.txt from your command line