Bit of background, I'm writing a program that plays the game "boxes" it runs in linux command line and is written in C. There's a prompt that waits for user input and then is read with fgets() and interpretted etc.
As part of the task specification I have to return a specific error if I reach "End of file while waiting for user input". I understand that fgets() returns null when it reaches EOF... but say I have
fgets(input,max_buffer,stdin);
in a prompt loop if the user exits prematurely say with CTRL+C or CTRL+D does this mean that input == NULL?
Can I even detect when a user does this with fgets?
Just trying to get my head around this, thanks in advance for any help.
(OS: UNIX)
(Compiler: gcc - c90)
From here, fgets:
Reads characters from stream and stores them as a C string into str until (num-1) characters have been read or either a newline or the end-of-file is reached, whichever happens first.
A newline character makes fgets stop reading, but it is considered a valid character by the function and included in the string copied to str.
A terminating null character is automatically appended after the characters copied to str.
So, fgets will return when the user inputs CTRL-D (end-of-file) or, when a \n (newline) is encountered. CTRL-C will by default terminate your program entirely.
If you'd like to catch CTRL-C, and exit gracefully, you could:
#include <signal.h>
void intHandler(int dummy) {
//graceful CTRL-C exit code.
}
int main(void) {
signal(SIGINT, intHandler);
//your code
}
The documentation (C99 ยง7.19.7.2):
The fgets function returns s if successful. If end-of-file is encountered and no characters have been read into the array, the contents of the array remain unchanged and a null pointer is returned. If a read error occurs during the operation, the array contents are indeterminate and a null pointer is returned.
So if an end-of-file occurs, but characters have been read, fgets will not return NULL. If EOF happens before any input was read, it will return NULL.
You can differentiate between EOF and a read error with the feof and ferror functions.
When the end-user exits permanently with Ctrl+C, your program loses control right away, meaning that you do not get any further input from fgets, not even a NULL.
Ctrl+D, on the other hand, closes the input stream without closing your program, so you would get a NULL result from the fgets call.
You can set your program up to handle Ctrl+C by handling a signal, but such handling would happen outside the input loop.
Related
In this code:
#include<stdio.h>
int main()
{
int i,p=0;
while(i!=EOF)
{
i=getchar();
putchar(i);
printf("\n");
}
return 0;
}
When I enter hello as input in one go, the output is h then in the next line e and so on. But when h is printed then before printing e why getchar() doesn't take pause to take input from me just like it did in the first time?
getchar() returns either any successfully read character from stdin or some error, so which function is demanding terminal input and then sending it to stdin?
Input from a terminal is generally buffered. This means it is held in memory waiting for your program to read it.
This buffer is performed by multiple pieces of software. The software that is actually reading your input in the terminal window generally accumulates characters you type until you press enter or press certain other keys or combinations that end the current input. Then the line that has been read is made available to your program.
Inside your program, the C standard library, of which getchar is a part, reads the data that has been sent to it and holds it in a buffer of its own. The getchar routine reads the next character from this buffer. (If the buffer is empty when getchar wants another character, getchar will block, waiting for new data to arrive from the terminal software.)
It's because of the loop condition. You are continuing to loop until EOF is received. When you type "hello", it works exactly as you expect except STDIN has more characters in the buffer and none of them are EOF. The program prints out "h", then a newline, and goes back to check the loop condition. EOF has not been found, so then it gets the next character from STDIN (which you have already provided) and the cycle repeats.
If you remove the loop it will only print one character.
Here is a basic character counting program in C:
#include <stdio.h>
#include <stdlib.h>
int main(){
long nc = 0;
while(getchar() != EOF)
nc++;
printf("%ld\n" , nc);
}
When I am entering "abcde" as an input, it displays a value of 6(after triggering the EOF test), +1 for the newline character. But my doubt is that getchar(), as its name itself suggests, takes only 1 character into account. But when I am entering "abcde" at one go itself, it still works. Why is this so? What problem am I doing here?
Standard input, by default, is line-buffered with an interactive device. This means that your program won't see any input at all until a complete line is ready, in your case when you hit Enter. One good reason for this is that if the user types her 8 character password, then hits backspace 8 times, and then types her username and hits Enter, then your program only gets her username, and never sees the correction, which is usually what you want when your shell gives the opportunity to edit your input before you send it anywhere.
So what happens is essentially this:
You call getchar(). No input is available, so it waits.
You press a. It's not the end of a line, so no input is sent to your program, getchar() has nothing to read, so it still waits.
You press b. It's not the end of a line, so no input is sent to your program, getchar() has nothing to read, so it still waits.
You press c. It's not the end of a line, so no input is sent to your program, getchar() has nothing to read, so it still waits.
You press d. It's not the end of a line, so no input is sent to your program, getchar() has nothing to read, so it still waits.
You press e. It's not the end of a line, so no input is sent to your program, getchar() has nothing to read, so it still waits.
You press Enter. Now it is the end of a line, so the input "abcde\n" is sent to your program.
getchar() now has input to read, so it returns 'a', increments nc, and loops back to wait for input.
Immediately, getchar() has more input to read from the rest of the characters in that line, so it returns 'b', increments nc, and loops back to wait for input.
Immediately, getchar() has more input to read from the rest of the characters in that line, so it returns 'c', increments nc, and loops back to wait for input.
Immediately, getchar() has more input to read from the rest of the characters in that line, so it returns 'd', increments nc, and loops back to wait for input.
Immediately, getchar() has more input to read from the rest of the characters in that line, so it returns 'e', increments nc, and loops back to wait for input.
Immediately, getchar() has more input to read from the rest of the characters in that line, so it returns '\n', increments nc, and loops back to wait for input.
If you signified end-of-input, perhaps by pressing Control-D, then getchar() has nothing to read and knows there will never be anything to read, so it returns EOF and your loop ends. If it were not end-of-input, then getchar() would just again wait here for you to enter a new line of input.
So what actually happened here is that getchar() did nothing until you hit Enter. Then, probably before you even took your finger off the Enter key, it ran six times and consumed the six characters of input that you typed. But despite getchar() running six times, you were only prompted to enter something once (twice, if you include having to type Control-D), because getchar() will only wait for your input when it doesn't already have input available and waiting.
Back in the days where standalone terminals were common, the actual terminal device might not even transmit any characters to the computer until the end of a line, and could have a small amount of on-board memory to allow for this kind of local line-based editing, so the computer itself might literally never see it until end-of-line. On the kind of modern PC many people use, the operating system, down at the terminal driver level, will more probably be buffering these characters itself, and just presenting them and making them available to your program one line at a time (unless you specifically tell it that you want characters immediately, of course).
When you type in abcde\n (\n generated from Enter), it gets flushed into the standard input stream (stdin).
getchar(), as its name itself suggests, takes only 1 character into account
Yes, that's right. But notice that getchar is used in a loop which loops until getchar returns EOF. Also, recall that getchar reads input from the stdin.
So, in the first iteration, after you type in the data, getchar reads the first character a. In the second iteration, it doesn't wait for input since the stdin still contains bcde\n and hence, reads the next character b and so on.
Finally, the loop breaks when you trigger EOF. Then, the printf gets executed (printing 6 since six characters were read) and the program ends.
getchar reads next characters from standard input's buffer, and returns it, since you feed six characters - "abcde\n" - into the standard input, and you are calling getchar in a while loop, that means the loop body was run for six times, it read the chars one by one. You can test this by:
int c;
while ((c = getchar()) != EOF) {
printf("got %c\n", c);
nc++;
}
What should this program do,
#include<stdio.h>
main()
{
getchar();
}
I expect it to show a blank screen until I hit any character on the keyboard. But what it does is quite weird. It displays whatever I press. It never terminates until I press Enter.
As far as I know, getchar() should just read one character. It should not output anything.
Why is it printing every character that I input?
Edit:
Why doesn't getchar() stop after reading one character, e.g. in this code:
#include <stdio.h>
main()
{
getchar();
printf("Done");
}
The program should print Done after reading one character.
Your program won't terminate until getchar() completes. getchar() does not complete until the input buffer is populated. The input buffer is not populated until you press 'Enter'.
The character you are seeing is the character you are typing. This is default terminal-driven behavior, not driven by your program.
You are pressing key, so your console is showing same character to you. It's expected behaviour. getch() will also return ascii value of character that is being printed on screen.
What getchar basically does is reading from stdin. This is a file with file descriptor 0 and it usually refers to the terminal that you type in (unless you change it to some file via <, e.g. cat < sample.txt). Like with any file, you can call read on file 0 - in case of the terminal, read will respond as soon as you type something into the terminal and hit enter. Unless you do so, the call to read on stdin just waits until it gets something to read. This is why your program is waiting: It calls read on stdin (file 0), and since stdin is the terminal, read will only return when you hit enter.
I hope you have some understanding on file handling, otherwise this answer might confuse you a bit.
char ch;
while((ch=getc(stdin))!=EOF)
{
putc(ch,stdout);
}
As we know that EOF character can be inputted by ctrl-z.
I ran the program two times:-
1- When I input ctrl-z, the loop gets terminated, which is acceptable.
2- When I input ctrl-z along with some other text like demo and then press ctrl-z, then the loop does not get terminated.
So my question is that why the loop is getting terminated only by inputing ctrl-z alone?
EOF is not a character that you can put into a stream. It's a meta-control character that can be returned by getc, but can not be written. ctrl-z does not technically send EOF, it sends SIGTSTP to the process and getc is programmed to respond to it by returning EOF.
char **query;
query = (char**) malloc ( sizeof(char*) );
int f=0;
int i=0,j=0,c;
while((c=getchar())!=EOF)
{
if(!isalpha(c))
continue;
if(f==1)
query=(char**) realloc(query,(i+1)*sizeof(char*));
query[i]=(char*) malloc(sizeof(char));
query[i][j]=c;
j++;
while( (c=getchar())!=EOF&&c!=' '&&c!='\t' )
{
query[i]=(char*) realloc(query[i],(j+1)*sizeof(char));
query[i][j]=c;
++j;
}
query[i][j]='\0';
printf("%s\n",query[i]);
if(c==EOF){
break;
}
++i;
f=1;
j=0;
}
I want the above code snippet to read a line of strings separated by spaces and tabs until ONE EOF but it requires 2 EOFs to end the loop. Also, strings can consist of only alphabetic characters.
I am struggling on about 2 days.
Please, give some feedback.
EDIT: Most probably the reason is I hit CTRL+D keys after I write last string not the enter key, but now I hit enter and then CTRL+D, it works as expected.
But, how can I change it to finish after I hit CTRL+D once following the last string?
On Unix-like systems (at least by default), an end-of-file condition is triggered by typing Ctrl-D at the beginning of a line or by typing Ctrl-D twice if you're not at the beginning of a line.
In the latter case, the last line you read will not have a '\n' at the end of it; you may need to allow for that.
This is specified (rather indirectly) by POSIX / The Open Group Base Specifications Issue 7, in section 11, specifically 11.1.9:
EOF
Special character on input, which is recognized if the ICANON flag is
set. When received, all the bytes waiting to be read are immediately
passed to the process without waiting for a <newline>, and the EOF is
discarded. Thus, if there are no bytes waiting (that is, the EOF
occurred at the beginning of a line), a byte count of zero shall be
returned from the read(), representing an end-of-file indication. If
ICANON is set, the EOF character shall be discarded when processed.
The POSIX read() function indicates an end-of-file (or error) condition to its caller by returning a byte count of zero, indicating that there are no more bytes of data to read. (C's <stdio> is, on POSIX systems, built on top of read() and other POSIX-specific functions.)
EOF (not to be confused with the C EOF macro) is mapped by default to Ctrl-D. Typing the EOF character at the beginning of a line (either at the very beginning of the input or immediately after a newline) triggers an immediate end-of-file condition. Typing the EOF character other than at the beginning of a line causes the previous data on that line to be returned immediately by the next read() call that asks for enough bytes; typing the EOF character again does the same thing, but in that case there are no remaining bytes to be read and an end-of-file condition is triggered. A single EOF character in the middle of a line is discarded (if ICANON is set, which it normally is).
In the off chance that someone sees this that needs the help I've been needing... I had been searching, trying to figure out why I was getting this strange behavior with my while(scanf). Well, it turns out that I had while (scanf("%s\n", string) > 0). The editor I am using (Atom) automatically put a "\n" in my scan, with out me noticing. This took me hours, and luckily someone pointed it out to me.
The Return key doesn't produce EOF that's why the condition getchar() != EOF doesn't recognize it. You can do it by Pressing CTRL+Z in Windows or CTRL+D in Unix.