K&R Exercise 1-8 Counting blanks, tabs, and new lines - c

I'm going through K&R's book, and one of the exercises is to count the blanks, tabs, and new lines from input. But whenever I run the following code, it only correctly counts the blanks, tabs, and new lines for everything above the last new line. If there's no new line, it doesn't count anything.
hey how
returns
0 0 0
and
hey how
hey how
hey how
returns
2 0 2
If I had tabbed instead of using spaces it would be 0 2 2.
The spaces and tabs seem dependent on the new line, and I don't know why. So how do I get this to work so it doesn't require a new line at the end?
Here's my code.
#include <stdio.h>
/* counts blanks, tabs, and new lines */
main()
{
int c, blanks, tabs, nl;
blanks = 0;
tabs = 0;
nl = 0;
while((c = getchar()) != EOF)
{
if(c == ' ')
++blanks;
if(c == '\t')
++tabs;
if(c == '\n')
++nl;
}
printf("\n%d\t%d\t%d\n" , blanks , tabs , nl);
}

Use a different keyboard shortcut. You don't want to kill the program, you want to simulate end-of-file with the appropriate key combination:
Ctrl+C: Kills the program.
Ctrl+Z, Enter: Signals EOF in Windows.
Ctrl+D: Signals EOF in Linux.

Related

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.

What is normal C getchar/putchar behaviour?

I am working through the exercises in Stephen Prata's "C Primer Plus", and have a question re. listing 8.1:
/* echo.c -- echoes input */
#include <stdio.h>
int main(void)
{
char ch;
while ((ch = getchar()) != '#')
putchar(ch);
// while ((ch = getchar()) != '.')
// putchar(ch);
return 0;
}
The original code did not include the comments; I added them and they are the subject of my question. If I uncomment those lines there is no discernible effect on the output. It still ends at the # sign, without printing it. No additional text is displayed and I am returned to the command prompt.
Why is that? Also, does the # get consumed by getchar()? That was why I included the second loop - I was trying to display any remaining characters in the buffer, out of curiosity. Obviously, I don't know what I'm doing!

Get input using tab instead of Enter key in C-Linux

Background:
I am developing linux-like shell in C. The first and basic requirement is to get infinite input (probably commands like rm kill etc. , which will execute) from user & upon Tab key, list of possible commands must be output to the screen.
Question:
My question is that how to get the input upon Tab Key press instead of Enter key?
A quick example will be very helpful, since I'm a college student learning C as part of OS course.
You want receive already entered chars for autocomplete?
I suggest you to get each key press separately.
Thus, it will always be known that user have already entered.
#include <stdio.h>
getchar()
or
#include <conio.h>
_getch()
https://en.wikibooks.org/wiki/A_Little_C_Primer/C_Console_IO
Tab is '\t' and Enter is '\n'
while ((c = getchar()) != EOF)
{
if (c == '\n')
++newlines;
else if (c == '\t')
++tabs;
else if (c == ' ')
++blanks;
if (c == EOL) {
printf("Lines: %d\nTabs: %d\nBlanks: %d\n", newlines, tabs, blanks);
}
}

Reading delete keystroke in c

I have encountered something I don't have a clear grasp on. I am having trouble reading the delete input from my MacBook Air. I am writing a program in c to read the input, and have used the following escape sequence character:
c = '127'
I can set the variable c to the decimal value of 8, which from my understanding is the backspace escape sequence. And also in Terminal>Preferences>Advanced, I check the box that enables delete to send Control-H.
Once I do the mentioned things above, I can read the input setting c variable as the following:
c = '8'
Here is my code to attempt to read the delete key from my MacBook
Air:
#include <stdio.h>
main() {
/* Copy program input to program output,
replacing each tab by \t,
each backspace by \b,
and each backslas by \\.
This makes tabs and backspaces visible in an unambiguous way.
*/
int c; // a variable for a character
while((c = getchar()) != EOF) {
if (c == '\t')
printf("\\t");
// check box found in:
// Terminal>Preferences>Advanced>Delete sends Control-H
// default setting DOES NOT send Control-H
// The Delete key does not appear to work with the ascii decimal character value 127.
if (c == '\127')
printf("Print to the screen if Delete key is detected.");
if (c == '\\')
printf("\\\\");
if (c != '\t')
if (c != '\b')
if (c != '\\')
putchar(c);
}
}
Try the following code and see what happens:
#include <stdio.h>
#include <stdlib.h>
int
main() {
int c;
system("stty raw -echo");
while (1) {
c = getchar();
if (c == 3) break; // exits when Ctrl-C is pressed
printf("pressed code: %d\r\n", c);
}
system("stty -raw echo");
return 0;
}
Hope this helps.
The reason that you can't read it is that it is not actually there. Using the delete code to delete characters is inefficient, so most programs actually delete the character instead of adding a delete character in order to hide the previous character.

count tabs in C (fails)

So, I'm supposed to be creating a program in C to count: "blanks, tabs, and spaces". My code is provided below (including comments). you'll see that I have commented the areas of the code that is tasked with counting, and displaying the count of, tabs.
As it stands, the program counts "Blanks" and "Lines" accurately, but "Tabs" always results in "0". I've combed over the tiny code again and again looking for typoes or something, but have found no reason why '\t' fails to be counted. Then I came here and read through a few posts dealing with this same challenge. Thus far, I have found nothing anywhere which would shed any light on the problem I am experiencing with my code.
please, look it over, compile it, and test it out yourself to verify.
If anyone can tell me where my mistake is, that is causing my code not to count "Tabs" (as desired), that would be fantastic.
thank you.
#include <stdio.h>
/* count blanks (" "), tabs (\t), and newlines (\n) */
main()
{
int c, nb, nt, nl;
nb = nt = nl = 0;
while ((c = getchar()) != EOF)
if (c == ' ')
++nb;
else if (c == '\t')
++nt; /* fails to accumulate count */
else if (c == '\n')
++nl;
printf("Spaces:\t%d\n", nb);
printf("Tabs:\t%d\n", nt); /* fails to report new tabs (\t) */
printf("Lines:\t%d\n", nl);
}

Resources