getchar() and conditioning a loop to break with a specific char - c

I am working on the infamous book "Prentice Hall Software Series" and trying out the Code they write and modifying it to learn more about C.
I am working with VIM on Fedora 25 in the console. The following code is a quote from the book, I know "int" is missing as well as argc and argv etc.
Kernighan and Ritchie - The C Programming Language: Page 20
#include <stdio.h>
/* copy input to output; 1st version */
main(){
int c;
c = getchar();
while (c != EOF) {
putchar(c);
c = getchar();
}
}
With this code I couldn't manage to get the "EOF" to work. I am not sure if "ctr + z" really is the real thing to do, since it quits any console program in console.
Well since I was unsure i changed the condition to
...
while (c != 'a') {
...
So normally if I enter 'a' the while condition should break and the programm should terminate. Well it does not when I try to run it and enter 'a'. What is the problem here?
Thank you guys!

There's nothing wrong with the code (except the archaic declaration of main).
Usually, on Unixes end of file is signalled to the program by ctrl-D. If you hit ctrl-D either straight away or after hitting new-line, your program will read EOF.
However, the above short explanation hides a lot of subtleties.
In Unix, terminal input can operate in one of two modes (called IIRC raw and cooked). In cooked mode - the default - the OS will buffer input from the terminal until it either reads a new line or a ctrl-D character. It then sends the buffered input to your program.
Ultimately, your program will use the read system call to read the input. read will return the number of characters read but normally will block until it has some characters to read. getchar then passes them one by one to its caller. So getchar will block until a whole line of text has been received before it processes any of the characters in that line. (This is why it still didn't work when you used a).
By convention, the read system call returns 0 when it gets end of file. This is how getchar knows to return EOF to the caller. ctrl-D has the effect of forcing read to read and empty buffer (if it is sent immediately after a new line) which makes it look to getchar like it's reached EOF even though nobody has closed the input stream. This is why ctrl-D works if it is pressed straight after new line but not if it is pressed after entering some characters.

Related

puts(), gets(), getchar(), putchar() function simultaneously use in the program

I have a confusion related to using puts(), gets(), putchar() and getchar() simultaneously use in the code.
When I have run the below code, it is doing all steps:
taking the input, printing the output, again taking the input, printing the output.
#include <stdio.h>
int main() {
char ch[34];
gets(ch);
puts(ch);
char g;
g = getchar();
putchar(g);
}
Output:
Priyanka
Priyanka
J
J
But, when I am using this code:
It is only doing two steps:
taking the input, printing the input, then one line space. I am not getting why it behaves like this.
Code:
#include <stdio.h>
int main() {
char g;
g = getchar();
putchar(g);
char ch[34];
gets(ch);
puts(ch);
getch();
}
Output:
P
P
There are some problems in the code and the input mechanisms are more complex than you infer:
you should not read input with gets(): this function cannot be used safely because it does not receive information about the destination array size so any sufficiently long input line will cause a buffer overflow. It has been removed from the C Standard. You should use fgets() instead and deal with the newline at the end of the buffer.
g should have type int to accommodate for all the values returned by getc(), namely all values of type unsigned char (in most current systems 0 to 255) and the special negative value EOF (usually -1).
Here is a modified version:
#include <stdio.h>
int main() {
char ch[34];
if (fgets(ch, sizeof ch, stdin))
fputs(ch, stdout);
int g = getchar();
if (g != EOF)
putchar(g);
return 0;
}
Output:
Priyanka
Priyanka
J
J
Regarding the behavior of the console in response to your program's input requests, it is implementation defined but usually involves 2 layers of buffering:
the FILE stream package implements a buffering scheme where data is read from or written to the system in chunks. This buffering can be controlled with setvbuf(). 3 settings are available: no buffering (which is the default for stderr), line buffered (usually the default for stdin and stdout when attached to a character device) and fully buffered with a customisable chunk size (common sizes are 512 and 4096).
when you call getchar() or more generally getc(stream), if a byte is available in the stream's buffer, it is returned and the stream position is incremented, otherwise a request is made to the system to fill the buffer.
if the stream is attached to a file, filling the buffer performs a read system call or equivalent, which succeeds unless at the end of file or upon a read error.
if the stream is attached to a character device, such as a terminal or a virtual tty like a terminal window on the graphics display, another layer of buffering gets involved where the device driver reads input from the input device and handles some keys in a special way such as Backspace to erase the previous character, cursor movement keys to move inside the input line, Ctrl-D (unix) or Ctrl-Z (windows) to signal the end of file. This layer of buffering can be controlled via the tcsetattr() system call or other system specific APIs. Interactive applications such as text editors typically disable this and retrieve raw input directly from the input device.
the keys typed by the user are handled by the terminal to form an input line, send back to the C stream API when the user types Enter (which is translated as a system specific end of line sequence), the stream functions perform another set of transformations (ie: converting CR/LF to '\n' on legacy systems) and the line of bytes is stored in the stream buffer. When getc() finally gets a chance to return the first available byte, the full line has already been typed and entered by the user and is pending in the stream or the device buffers.
In both programs, getchar() does not return the next byte read from stdin until a full line has been read from the terminal and stored in the stream buffer. In the first program, the rest of this line is ignored as the program exits, but in the second program, the rest of this line is available for the subsequent gets() to read. If you typed J and Enter, the line read is J\n and getchar() returns the 'J', leaving the newline [ending in the input stream, then gets() will read the newline and return an empty line.
Between the lines of the statements putchar() and gets() that I don't recommend using, discarding the input stream until EOF or till a newline occurs solves the problem:
.
.
int c;
while ((c = getchar()) != EOF && c != '\n')
;
.
.
I would recommend using fgets(3) which is quite safer to use, for example:
char str[1024];
if (fgets(str, sizeof str, stdin) == NULL) {
// Some problem, handle the error...
}
// or, Input is okay...
Well, you have a problem here. You use a function in your second sample code that is not part of the stdio package.
You call getch() which is not a stdio function. It is part of the ncurses library, and, if you don't specify on compilation that you will use it, then you cannot get an executable program. So this make me thing you are not telling all the truth.
Just taking the function getch() of of the program you get the full line
Priyanka
output, and the program terminated. I guess you used getch() to stop the output until you press a character. But as curses library requires you to call initscr() before calling any other curses library function, it is not correctly initialized, and the output you get can be wrong due to this.
I'll not repeat what others have already told you about the use of gets(), it is still in the standard library, and knowing what you do, you can still use it in properly controlled environments. Despite of that, the recommendation others have given to you is not applicable here, as you have not overflowed the short buffer you have used (of only 34 chars, too short, too easy to hang your program or to crash it)
The functions from stdio use a buffer, and the unix tty driver is also interferring here. Your terminal will not make available any character you input to the program until you press the <ENTER> key, then all those characters are read by the program into a buffer. They are consumed from the buffer, until it is empty, so it doesn't matter if you read them one by one (with fgetch(), or all at once (with fgets() ---i'll use this, more secure, function, from this point on) Everything just happens once you press the <ENTER> key.
fgetch() only takes one character, so if more than one are available, only one character is taken from the buffer, and the rest wait their turn. But fgets() reads all (and fills the buffer) until a \n is read (this is why gets() is so dangerous, because it doesn't know the size of your buffer /it doesn't have a parameter indicating the size of the buffer, as fgets() has/ and cannot control the read to stop before overflowing it)
So, in your case, as you press a series of characters, then hit return, the first sample reads the full string, and then the second getchar() takes the first of the second line (but you need to input two complete lines at that point) The second sample read the first char when you called getchar(), and the rest of the line when you called gets().
To read one character at a time, without waiting for a full line to be input, the terminal driver has to be programmed to read characters in raw mode. Cookied mode (the default) is used by unix to read complete lines, this allows you to edit, erase characters on the line, and only input it when you are ready and hit the <ENTER> key.
If you are interested in reading chars one by one from the terminal, read the manual page termios(4) which explains the interface and iocontrols to the tty device. The curses library does the necessary housekeeping to put the terminal in raw mode to allow programs like vi(1) to read the input char by char, but you need then not to use stdio directly, as its buffering system will eat the characters you try to get to eat with curses.

getchar() is giving output in C

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.

C, while loop keeps repeating

so I built a very basic program according to The C Programming Language book, but when I run it, it keeps asking input after I enter one, the loop should ended when there are no inputs longer right? or Am I wrong? srry for my bad english
int main()
{
long nc;
nc = 0;
while ( getchar() != EOF) {
++nc;
}
printf("%ld\n", nc);
}
Your loop is expecting an EOF character to terminate, not just an empty string. *nix consoles typically translate a Ctrl-D on an empty line as EOF, in Windows I believe it's Ctrl-Z but I could be wrong.
No.
For standard input, you must input EOF manually. It's Ctrl+Z in Windows and Ctrl+D in Linux.
If you are using Linux and redirect standard input from file. It will end.
This will keep reading input until it gets to an end-of-file. If you're reading from the terminal (you haven't redirected the program to read from a file), it will only get an EOF if you explicitly give it one. How you do that dpends on your OS, but on most UNIX-like systems, you can generate an explicit eof by hitting ctrl-D
You can press the Ctrl + D to input EOF, anything other keyboard can't! So if you want to interrupt the loop, you must input the EOF.

Input for examples from Kernighan and Ritchie

In section 1.5.2 of the 2nd ed. K&R introduce getchar() and putchar() and give an example of character counting, then line counting, and others throughout the chapter.
Here is the character counting program
#include <stdio.h>
main() {
long nc;
nc = 0;
while (getchar() != EOF)
++nc;
printf("%ld\n",nc);
}
where should the input come from? typing into the terminal command window and hitting enter worked for the file copying program but not for this. I am using XCode for Mac.
It seems like the easiest way would be to read a text file with pathway "pathway/folder/read.txt" but I am having trouble with that as well.
From the interactive command line, press ctrl-D after a newline, or ctrl-D twice not after newline, to terminate the input. Then the program will see EOF and show you the results.
To pass a file by path, and avoid the interactive part, use the < redirection operator of the shell, ./count_characters < path/to/file.txt.
Standard C input functions only start processing what you type in when you press the Enter key IOW.Every key you press adds a character to the system buffer (shell).Then when the line is complete (ie, you press Enter), these characters are moved to C standard buffer. getchar() reads the first character in the buffer, which also removes it from the buffer.Each successive call to getchar() reads and removes the next char, and so on. If you don't read every character that you had typed into the keyboard buffer, but instead enter another line of text, then the next call to getchar() after that will continue reading the characters left over from the previous line; you will usually witness this as the program blowing past your second input. BTW, the newline from the Enter key is also a character and is also stored in the keyboard buffer, so if you have new input to read in you first need to clear out the keyboard buffer.

Where does `getchar()` store the user input?

I've started reading "The C Programming Language" (K&R) and I have a doubt about the getchar() function.
For example this code:
#include <stdio.h>
main()
{
int c;
c = getchar();
putchar(c);
printf("\n");
}
Typing toomanychars + CTRL+D (EOF) prints just t. I think that's expected since it's the first character introduced.
But then this other piece of code:
#include <stdio.h>
main()
{
int c;
while((c = getchar()) != EOF)
putchar(c);
}
Typing toomanychars + CTRL+D (EOF) prints toomanychars.
My question is, why does this happens if I only have a single char variable? where are the rest of the characters stored?
EDIT:
Thanks to everyone for the answers, I start to get it now... only one catch:
The first program exits when given CTRL+D while the second prints the whole string and then waits for more user input. Why does it waits for another string and does not exit like the first?
getchar gets a single character from the standard input, which in this case is the keyboard buffer.
In the second example, the getchar function is in a while loop which continues until it encounters a EOF, so it will keep looping and retrieve a character (and print the character to screen) until the input becomes empty.
Successive calls to getchar will get successive characters which are coming from the input.
Oh, and don't feel bad for asking this question -- I was puzzled when I first encountered this issue as well.
It's treating the input stream like a file. It is as if you opened a file containing the text "toomanychars" and read or outputted it one character at a time.
In the first example, in the absence of a while loop, it's like you opened a file and read the first character, and then outputted it. However the second example will continue to read characters until it gets an end of file signal (ctrl+D in your case) just like if it were reading from a file on disk.
In reply to your updated question, what operating system are you using? I ran it on my Windows XP laptop and it worked fine. If I hit enter, it would print out what I had so far, make a new line, and then continue. (The getchar() function doesn't return until you press enter, which is when there is nothing in the input buffer when it's called). When I press CTRL+Z (EOF in Windows), the program terminates. Note that in Windows, the EOF must be on a line of its own to count as an EOF in the command prompt. I don't know if this behavior is mimicked in Linux, or whatever system you may be running.
Something here is buffered. e.g. the stdout FILE* which putchar writes to might be line.buffered. When the program ends(or encounters a newline) such a FILE* will be fflush()'ed and you'll see the output.
In some cases the actual terminal you're viewing might buffer the output until a newline, or until the terminal itself is instructed to flush it's buffer, which might be the case when the current foreground program exits sincei it wants to present a new prompt.
Now, what's likely to be the actual case here, is that's it's the input that is buffered(in addition to the output :-) ) When you press the keys it'll appear on your terminal window. However the terminal won't send those characters to your application, it will buffer it until you instruct it to be the end-of-input with Ctrl+D, and possibly a newline as well.
Here's another version to play around and ponder about:
int main() {
int c;
while((c = getchar()) != EOF) {
if(c != '\n')
putchar(c);
}
return 0;
}
Try feeding your program a sentence, and hit Enter. And do the same if you comment out
if(c != '\n') Maybe you can determine if your input, output or both are buffered in some way.
THis becomes more interesting if you run the above like:
./mytest | ./mytest
(As sidecomment, note that CTRD+D isn't a character, nor is it EOF. But on some systems it'll result closing the input stream which again will raise EOF to anyone attempting to read from the stream.)
Your first program only reads one character, prints it out, and exits. Your second program has a loop. It keeps reading characters one at a time and printing them out until it reads an EOF character. Only one character is stored at any given time.
You're only using the variable c to contain each character one at a time.
Once you've displayed the first char (t) using putchar(c), you forget about the value of c by assigning the next character (o) to the variable c, replacing the previous value (t).
the code is functionally equivalent to
main(){
int c;
c = getchar();
while(c != EOF) {
putchar(c);
c = getchar();
}
}
you might find this version easier to understand. the only reason to put the assignment in the conditional is to avoid having to type 'c=getchar()' twice.
For your updated question, in the first example, only one character is read. It never reaches the EOF. The program terminates because there is nothing for it to do after completing the printf instruction. It just reads one character. Prints it. Puts in a newline. And then terminates as it has nothing more to do. It doesn't read more than one character.
Whereas, in the second code, the getchar and putchar are present inside a while loop. In this, the program keeps on reading characters one by one (as it is made to do so by the loop) until reaches reaches the EOF character (^D). At that point, it matches c!=EOF and since the conditions is not satisfied, it comes out of the loop. Now there are no more statements to execute. So the program terminates at this point.
Hope this helps.

Resources