Exercise 1-8. Write a program to count blanks, tabs, and newlines.
Approach
The solution maintains three independent counters and reads one character at a time using the canonical getchar() loop. The key design decision is using three separate if statements rather than else if. In this case a character can only ever be one thing — a space, a tab, or a newline — so else if would work, but the three-if form makes each test independent and explicit, which is the style K&R use here to introduce the pattern cleanly.
One important detail: c must be declared as int, not char. The value EOF is typically -1, and on platforms where char is unsigned, a char can never hold -1, making the loop condition always false. Declaring c as int avoids this portability trap — it is the same reason K&R use int throughout Chapter 1.
Solution
/* K&R Exercise 1-8 — count blanks, tabs, and newlines */
/* Compile: gcc -ansi -Wall ex1-8.c -o ex1-8 */
#include <stdio.h>
int main(void)
{
int c, blanks, tabs, newlines;
blanks = tabs = newlines = 0;
while ((c = getchar()) != EOF) {
if (c == ' ')
++blanks;
if (c == '\t')
++tabs;
if (c == '\n')
++newlines;
}
printf("blanks: %d\ntabs: %d\nnewlines: %d\n", blanks, tabs, newlines);
return 0;
}
Line-by-Line Walkthrough
Chain assignment — blanks = tabs = newlines = 0 initialises all three counters in one statement. Assignment is right-associative in C: it evaluates as blanks = (tabs = (newlines = 0)).
The input loop — while ((c = getchar()) != EOF) is the canonical K&R idiom for reading until end of file. The inner parentheses around c = getchar() are required: without them, = has lower precedence than !=, and the compiler would compare the return value of getchar() against EOF first, then assign the boolean result (0 or 1) to c. This idiom was explained in detail in Exercise 1-6.
Three separate if statements — each character is tested against all three conditions on every pass through the loop. This differs from if / else if / else: with else if, once one condition matches, the others are skipped. Here it makes no practical difference because no character can simultaneously be a blank, a tab, and a newline — but the pattern keeps each test independent, which is useful when conditions are not mutually exclusive in more general programs.
Escape sequences — '\t' is the tab character (ASCII 9) and '\n' is the newline character (ASCII 10). Omitting the backslash — comparing against 't' or 'n' — would count the literal letters t and n, a silent bug that produces wrong results.
Compile and Run
gcc -ansi -Wall ex1-8.c -o ex1-8
./ex1-8
The program reads from standard input and waits for you to type. When you are done, signal end-of-file: press Ctrl+D on Linux/macOS or Ctrl+Z then Enter on Windows.
You can also pipe input directly so you do not have to type interactively:
echo "hello world" | ./ex1-8
printf "one\ttwo\tthree\nfour five\n" | ./ex1-8
Sample Runs
Run 1 — simple sentence with a trailing newline
$ echo "hello world" | ./ex1-8 blanks: 1 tabs: 0 newlines: 1
echo appends a newline automatically, so there is one newline even though you only typed one line.
Run 2 — tabs and multiple lines
$ printf "one\ttwo\tthree\nfour five six\n" | ./ex1-8 blanks: 2 tabs: 2 newlines: 2
Two tab-separated words on the first line give 2 tabs; two spaces on the second line give 2 blanks; each \n gives one newline.
Run 3 — interactive session
$ ./ex1-8 hello world [Tab key] C programming ^D blanks: 4 tabs: 1 newlines: 2
After pressing Ctrl+D the program prints the totals and exits.
What This Exercise Teaches
- Character-level I/O —
getchar()reads one character at a time, giving complete control over processing; this is the foundation of most text-processing programs in C. - The
int crule —EOFis an integer sentinel outside thecharrange; always useintfor variables that holdgetchar()return values. - Escape sequences as character literals —
'\t'and'\n'are single characters, each fitting in anint; the backslash is part of the literal, not a separate character. - Chain assignment —
a = b = c = 0is idiomatic C for initialising multiple variables to the same value in one statement. - Independent vs. mutually exclusive conditions — understanding when to use
if / if / ifvs.if / else if / elseis a foundational control-flow decision.
Set Up Your C Environment
To compile and run this program you need GCC installed. If you have not set up C on your machine yet:
- Complete C Development Environment Setup — start here if you are new
- Install GCC on Windows 11
- Install GCC on macOS
- Install GCC on Ubuntu/Linux
- VS Code for C Programming — recommended editor
← Exercise 1-7 |
Chapter 1 Solutions |
Exercise 1-9 →
Book:
The C Programming Language, 2nd Ed — Kernighan & Ritchie