K&R C Exercise 1-14: Histogram of Character Frequencies

Exercise 1-14. Write a program to print a histogram of the frequencies of different characters in its input.

Approach

The key insight here is one of the most elegant idioms in C: a character read from getchar() is already an integer — its ASCII value. That value falls in the range 0–127, so it can be used directly as an array index. Writing ++freq[c] is all it takes to tally a character; no lookup table, no conversion, no hash function. The same structure appeared in Exercise 1-13 for word lengths — only the accumulation key changed from word length to ASCII value. Recognising this general pattern (read a value, use it as an index, increment) is worth more than any single solution.

One practical wrinkle: characters 0–31 are control codes (tab, newline, bell, …). We count every character faithfully, but we only print histogram rows for the printable range (ASCII 32–126) to avoid corrupting the terminal output.

Solution

/* K&R Exercise 1-14 — character frequency histogram
 * Compile: gcc -ansi -Wall ex1-14.c -o ex1-14 */

#include <stdio.h>
#define MAXCHAR 128     /* covers full ASCII range */

int main(void)
{
    int c, i, j;
    int freq[MAXCHAR];

    for (i = 0; i < MAXCHAR; i++)
        freq[i] = 0;

    while ((c = getchar()) != EOF)
        if (c >= 0 && c < MAXCHAR)
            ++freq[c];

    /* print horizontal histogram — printable ASCII only (32-126) */
    for (i = 32; i < MAXCHAR; i++) {
        if (freq[i] > 0) {
            printf("'%c' | ", i);
            for (j = 0; j < freq[i]; j++)
                putchar('*');
            putchar('\n');
        }
    }
    return 0;
}

Compile and Run

gcc -ansi -Wall ex1-14.c -o ex1-14
echo "hello world" | ./ex1-14

Sample Output

Input: hello world (plus a trailing newline from echo)

' ' | *
'd' | *
'e' | *
'h' | *
'l' | ***
'o' | **
'r' | *
'w' | *

Notice that the newline character (ASCII 10) is counted but not displayed — it is below the printable threshold of 32. The space between “hello” and “world” is ASCII 32, so it does appear as the first row. Characters are shown in ASCII order because the output loop walks the array from index 32 upward.

How It Works: The Array-as-Frequency-Table Idiom

When getchar() returns 'h', the value it returns is the integer 104 — 'h'‘s ASCII code. The statement ++freq[104] increments the tally for that slot. No conversion step is needed because in C a char and an int differ only in width; the same bit pattern that spells a character also spells an array index.

The bounds check if (c >= 0 && c < MAXCHAR) guards against implementations where char is signed and a high-bit character could produce a negative value — an easy out-of-bounds bug to miss on first reading.

Contrast with Exercise 1-13: that program used word length as the index into a frequency array. Here we use the character’s ASCII value. The loop structure, the counting idiom, and the histogram-printing logic are identical. The pattern is: map the thing you want to count onto an integer, use that integer as an index. Once you see it here you will recognise it in hash tables, bucket sorts, and character classification tables throughout the rest of K&R.

What This Exercise Teaches

  • Characters as integers: in C, char is a numeric type; its value is the character’s ASCII code and can be used anywhere an integer is expected — including as an array subscript.
  • Frequency tables via direct indexing: allocating an array of size equal to the range of possible values and using each value as its own index is a fundamental C (and systems-programming) idiom.
  • Bounds checking on input: the c >= 0 && c < MAXCHAR guard prevents undefined behaviour when char is signed — a real portability concern, not just theoretical caution.
  • Separating counting from display: counting every character (including control codes) but only displaying the printable range keeps the logic clean and the output readable — a small but useful design decision.

Set Up Your C Environment

To compile and run this solution you need GCC installed. If you haven’t set up C on your machine yet:

← Exercise 1-13  | 
Chapter 1 Solutions  | 
Exercise 1-15 →

Book:
The C Programming Language, 2nd Ed — Kernighan & Ritchie

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>