Unexpected output while reading string from a keyboard - c

This program is returning something which I'm not able to comprehend. Attached is the screenshot of the O/P simple program to find number of spaces, tabs, etc.
What am I missing?
#include <stdio.h>
#include <string.h>
int main() {
int count[] = { 0, 0, 0 }; /* 0 is spaces, 1 is tabs and 2 for newline. */
int string;
printf("Enter the paragraph: \n");
while ((string = getchar()) != EOF) {
if (string == ' ')
count[0]++;
else if (string == '\t')
count[1]++;
else if (string == '\n')
count[2]++;
}
printf("There are %d Spaces.\n", count[0]);
printf("There are %d Tabs.\n", count[1]);
printf("There are %d Newlines.\n", count[2]);
return 0;
}

From the screenshot it appears you typed Ctrl-Z to signal the end of file to your program. While this works in legacy systems such as MS/DOS and the Windows terminals, this key combination has a different meaning on unix systems such as linux: it causes the current process to be suspended by its the running shell parent. The process can be resumed later with the fg command.
To signal the end on file on this system, you should type Ctrl-D instead.
Your program should produce the expected result then. The code seems OK, albeit it is quite confusing to name string an int variable that gets a single byte from getchar(). Such a variable is usually named c.

If you want to send an EOF in order to stop reading you should use CTRL+D.

Related

Confused about EOF for scanf() in C [duplicate]

I'm practicing using C & Unix by writing up some of the C programs in Vim and compiling them.
The word count program is supposed to end when the character read is EOF (CTRL-D). However, when I run it, the first CTRL-D pressed just makes it print "^D" (minus the quotes) on the terminal. The second time it's pressed, the "^D" goes away and it terminates normally.
How can I change this so that it terminates after only one CTRL-D? I notice that if I've just made a newline character, then pressing CTRL-D once does the trick. But I don't really understand why it works then and not in the general case.
Here's what the program looks like for those of you who don't have the book.
#include <stdio.h>
#define IN 1 /* Inside a word */
#define OUT 0 /* Outside a word */
int main()
{
int c, nl, nw, nc, state;
state = OUT;
nl = nw = nc = 0;
while ((c = getchar()) != EOF) {
++nc;
if (c == '\n') {
++nl;
--nc;
}
if (c == ' ' || c == '\n' || c == '\t')
state = OUT;
else if (state == OUT) {
state = IN;
nw++;
}
}
printf("%d %d %d\n", nl, nw, nc);
return 0;
}
Input in Unix-type systems is typically taken from a shell, most often in canonical mode, which means that it is partially interpeted by the shell in order to implement important control functions that govern how the command is used. An example of such a control function is to use control-X to clear the current line. What is happening in your case is that the shell (for example, bash) is interpreting the control-D as a user command to close the stream of input. All prior characters get sent to your program, as well as a control-D -- but the control-D has not been converted to an EOF. When all characters have already been sent on, as is the case following a new line, then bash does not intercept the control-D function but re-interprets control-D as a stand-alone input which it translates to indicate EOF. This EOF then successfully closes your program out.
For further information see prior answer:
ctrl-d didn't stop the while(getchar()!=EOF) loop
If you type Control-D at the start of the line, once should be enough. If you type Control-D after you've typed anything, then you need to type it twice.
That's because the Control-D tells the terminal driver to send all available characters to any waiting process. When it is at the start of a line, there are no available characters, so a process waiting on a read() gets zero characters returned, which is the meaning of EOF (no characters available for reading). When it is part way through a line, the first Control-D sends the characters to the program, which reads them; the second indicates no more characters and hence EOF once more.

K&R Chapter 1.5.4: "How would you test the word count program?"

Beginner here.
In the ANSI C textbook by K&R, page 20, they ask: How would you test the word count program?
I have copied exactly from the text book, using the CodeBlocks IDE, console application. I have seen many great input tests online, but my question is even dumber. How do I actually input something? Nothing happens when I press enter. Do I have this problem because I am using an IDE and therefore not learning how to run C programs properly?
Thanks in advance. I added a picture to show you what I mean
Here is the code:
#include <stdio.h>
#define IN 1 /* inside a word */
#define OUT 0 /* outside a word */
/* counts lines, words and characters as input */
main()
{
int c, nl, nw, nc, state;
state = OUT;
/* set these three constants to 0: */
nl = nw = nc = 0;
while ((c = getchar()) != EOF){
++nc;
if (c == '\n')
++nl;
/* || == OR (&& == AND)
evaluation of the following line
will stop as soon as the truth or
falsehood is known, so the order matters */
if (c == ' ' || c == '\n' == c == '\t')
state = OUT;
else if (state == OUT){
state = IN;
++nw;
}
}
printf("%d %d %d\n", nl, nw, nc);
}
On MacOS:
gcc kr_wc.c -o kr_wc
./kr_wc < example_text.txt
Example output:
40 260 1397
Where example_text.txt is this file:
1.5.4 Word Counting
The fourth in our series of useful programs counts lines, words, and
characters, with the loose definition that a word is any sequence of
characters that does not contain a blank, tab or newline. This is a
bare-bones version of the UNIX program wc.
#include <stdio.h>
#define IN 1 /* inside a word */
#define OUT 0 /* outside a word */
/* count lines, words, and characters in input */
int main() {
int c, nl, nw, nc, state;
state = OUT;
nl = nw = nc = 0;
while ((c = getchar()) != EOF) {
++nc;
if (c == '\n')
++nl;
if (c == ' ' || c == '\n' || c == '\t')
state = OUT;
else if (state == OUT) {
state = IN;
++nw;
}
}
printf("%d %d %d\n", nl, nw, nc);
}
Every time the program encounters the first character of a word, it
counts one more word. The variable state records whether the program
is currently in a word or not; initially it is "not in a word", which
is assigned the value OUT. We prefer the symbolic constants IN and
OUT to the literal values 1 and 0 because they make the program more
readable. In a program as tiny as this, it makes little difference,
but in larger programs, the increase in clarity is well worth the
modest extra effort to write it this way from the beginning. You'll
also find that it's easier to make extensive changes in programs
where magic numbers appear only as symbolic constants.
The program to count words in K&R 2nd edition is made to run on an environment in which you signal the end of input somehow. Normally, as they used UNIX all the time, they used Ctrl-D sequence (which is valid if you run the program in Linux or any Unix-like operating system) This has been so since the early beginning of the UNIX system.
Windows signals the end of input in a console application by the input of a Ctrl-Z (probably followed by a keyboard return key)
If you redirect the input from a file (as when you say a.out <my_input_file.txt) you'll get the number of words at the end, when there's no more input in the file.
You are running the program in an IDE, which is something that normally hides you where standard input and standard output go, or how to signal the window you show how to say that there's not more input to the program.
For the program to get to it's end, you have first to know how to get to an end on input.
The examples in K&R omit a return type of main, which is not valid in modern C, so add int before main():
#include <stdio.h>
#define IN 1 /* inside a word */
#define OUT 0 /* outside a word */
/* counts lines, words and characters as input */
int main()
{
int c, nl, nw, nc, state;
state = OUT;
/* set these three constants to 0: */
nl = nw = nc = 0;
while ((c = getchar()) != EOF){
++nc;
if (c == '\n')
++nl;
/* || == OR (&& == AND)
evaluation of the following line
will stop as soon as the truth or
falsehood is known, so the order matters */
if (c == ' ' || c == '\n' == c == '\t')
state = OUT;
else if (state == OUT){
state = IN;
++nw;
}
}
printf("%d %d %d\n", nl, nw, nc);
}
"How do I actually input something? Nothing happens when I press enter."
If you got problems with your IDE just run it online.
"How would you test the word count program"?
To cite the authors of a bundle of K&R solutions with an answer to that particular question here:
It sounds like they are really trying to get the programmers to learn how to do a unit test. I would submit the following:
input file contains zero words
input file contains 1 enormous word without any newlines
input file contains all white space without newlines
input file contains 66000 newlines
input file contains word/{huge sequence of whitespace of different >kinds}/word
input file contains 66000 single letter words, 66 to the line
input file contains 66000 words without any newlines
input file is /usr/dict contents (or equivalent)
input file is full collection of moby words
input file is binary (e.g. its own executable)
input file is /dev/null (or equivalent)
66000 is chosen to check for integral overflow on small integer machines.

Closing then opening standard input in C under Linux

I have a C console application under Linux (Raspbian - Raspberry Pi). The program has some character animation - it prints out messages character by character. For example, the text
Please give me your name!
is printed out completely after 5 seconds (char by char).
Afterwards, the user is asked to type in their name, which works just fine if the user waits for the message to be printed out. However, if the user is impatient and hits the keys on the keyboard randomly, the input request later is compromised.
Imagine the user types in
abc\nefgh\n
while the above text is being echoed ('\n' means new line - enter). If that happens, the user will not be asked to properly type in his/her name, but the array of characters 'abc' will be accepted as input and gets validated.
My question is how to disable input (buffering) temorarily (on Linux). I have tried several methods and read numerous posts about doing so, but none of them worked for my purpose.
The function that is responsible for asking for input is as follows:
int getLine(char *s, int length)
{
int i;
char c;
for (i = 0; i < length && (c = getchar()) != EOF && c != '\n'; i++)
{
if (c == '\0')
{
i--;
}
else
{
s[i] = c;
}
}
s[i] = '\0';
while (c != EOF && c != '\n')
{
c = getchar();
}
return i;
}
Empty lines are eliminated with the help of a while loop in the function calling the one above so enter inputs are considered invalid.
I tried closing stdin, but could not reopen it:
fclose(stdin);
and emptying buffer before the getLine:
char buf[BUFSIZ];
while (c = fgets(buf, BUFSIZ, stdin) != NULL);
Unfortunately, it did not work as it does with text files.
fflush(stdin); did not work either and is not pretty anyway.
My goal is to prevent users from typing in anything while the text is being written out and to ignore/close input buffering (stdin) temporarily. Also, it would be great to disable outputting (flushing) user inputs during printing as it gets displayed on Linux terminal.
You may do this by interacting with TTY directly. Look into source code of passwd or similar utilities for inspiration.
Function below clears TTY input buffer (error handling omitted). You need to call it just before reading user input.
#include <sys/ioctl.h>
#include <termios.h>
void clear_user_input() {
if (isatty(STDIN_FILENO)) {
int fd = open(ttyname(STDIN_FILENO), O_RDONLY);
ioctl(fd, TCFLSH, TCIFLUSH);
close(fd);
}
}

How can I make the word count program (from K&R) terminate after just one application of CTRL-D?

I'm practicing using C & Unix by writing up some of the C programs in Vim and compiling them.
The word count program is supposed to end when the character read is EOF (CTRL-D). However, when I run it, the first CTRL-D pressed just makes it print "^D" (minus the quotes) on the terminal. The second time it's pressed, the "^D" goes away and it terminates normally.
How can I change this so that it terminates after only one CTRL-D? I notice that if I've just made a newline character, then pressing CTRL-D once does the trick. But I don't really understand why it works then and not in the general case.
Here's what the program looks like for those of you who don't have the book.
#include <stdio.h>
#define IN 1 /* Inside a word */
#define OUT 0 /* Outside a word */
int main()
{
int c, nl, nw, nc, state;
state = OUT;
nl = nw = nc = 0;
while ((c = getchar()) != EOF) {
++nc;
if (c == '\n') {
++nl;
--nc;
}
if (c == ' ' || c == '\n' || c == '\t')
state = OUT;
else if (state == OUT) {
state = IN;
nw++;
}
}
printf("%d %d %d\n", nl, nw, nc);
return 0;
}
Input in Unix-type systems is typically taken from a shell, most often in canonical mode, which means that it is partially interpeted by the shell in order to implement important control functions that govern how the command is used. An example of such a control function is to use control-X to clear the current line. What is happening in your case is that the shell (for example, bash) is interpreting the control-D as a user command to close the stream of input. All prior characters get sent to your program, as well as a control-D -- but the control-D has not been converted to an EOF. When all characters have already been sent on, as is the case following a new line, then bash does not intercept the control-D function but re-interprets control-D as a stand-alone input which it translates to indicate EOF. This EOF then successfully closes your program out.
For further information see prior answer:
ctrl-d didn't stop the while(getchar()!=EOF) loop
If you type Control-D at the start of the line, once should be enough. If you type Control-D after you've typed anything, then you need to type it twice.
That's because the Control-D tells the terminal driver to send all available characters to any waiting process. When it is at the start of a line, there are no available characters, so a process waiting on a read() gets zero characters returned, which is the meaning of EOF (no characters available for reading). When it is part way through a line, the first Control-D sends the characters to the program, which reads them; the second indicates no more characters and hence EOF once more.

count the number of lines, words, and characters within an input

Right now I am going through a book on C and have come across an example in the book which I cannot get to work.
#include <stdio.h>
#define IN 1
#define OUT 0
main()
{
int c, nl, nw, nc, state;
state = OUT;
nl = nw = nc = 0;
while ((c = getchar()) != EOF) {
++nc;
if (c == '\n')
++nl;
if (c == ' ' || c == '\n' || c == '\t')
state = OUT;
else if (state == OUT) {
state = IN;
++nw;
}
}
printf("%d %d %d\n", nl, nw, nc);
}
It's supposed to count the number of lines, words, and characters within an input. However, when I run it in the terminal it appears to do nothing. Am I missing something or is there a problem with this code?
The program only terminates when the input ends (getchar returns EOF). When running on terminal, this normally never happens and because of this it seems that the program is stuck. You need to close the input manually by pressing Ctrl+D (possibly twice) on Linux or pressing F6 and Enter at the beginning of the line on Windows (different systems may use different means for this).
It's waiting for input on stdin. Either redirect a file into it (myprog < test.txt) or type out the data and hit Ctrl-D (*nix) or Ctrl-Z (Windows).
When you run it, you need to type in your text, press return, then type Ctrl-d and return (nothing else on the line) to signify end-of-file. Seems to work fine with my simple test.
What it is doing is entering a loop for input. If you enter a character or newline, nothing happens on the screen. You need to interrupt the process (on my Mac this is CTRL+D) which serves as EOF. Then, you will get the result.
getchar() returns the input from the standard input. Start typing the text for which you want to have the word count and line count. Your input terminates when EOF is reached, which you do by hitting CTRL D.
CTRL D in this case acts as an End Of Transmission character.
cheers
I usually handle this kind of input like this (for Linux):
1. make a file (for example, named "input.txt"), type your input and save
2. use a pipe to send the text to your application (here assume your application named "a.out" and in the current directory):
cat input.txt | ./a.out
you'll see the program running correctly.

Resources