Exercise 2-4. Write an alternative version of
squeeze(s1,s2)that deletes each character ins1that matches any character in the strings2.
Approach
The original K&R squeeze(s, c) removes all occurrences of a single character c from string s using a compact two-index pattern: index i scans every position in s, while index j only advances when a character is worth keeping. This exercise generalises that idea — instead of comparing against one character, you search an entire string s2 for each character of s1.
The key insight is the inner loop’s exit condition. The loop over s2 terminates in exactly two ways: either it found the character (s2[k] == s1[i]) or it ran off the end of s2 (s2[k] == '\0'). After the loop you test which case occurred: s2[k] == '\0' means the character was not in s2, so it survives. This “loop-then-test” idiom is a recurring pattern in C string handling — it appears in strchr, strpbrk, and countless hand-rolled searches.
Solution
/* compile: gcc -ansi -Wall ex2-4.c -o ex2-4 */
#include <stdio.h>
void squeeze(char s1[], const char s2[]);
int main(void)
{
char s1[] = "hello, world!";
char s2[] = "aeiou";
printf("Before: %s\n", s1);
squeeze(s1, s2);
printf("After: %s\n", s1);
char t1[] = "programming";
char t2[] = "mg";
printf("Before: %s\n", t1);
squeeze(t1, t2);
printf("After: %s\n", t1);
return 0;
}
/* squeeze: delete all chars in s1 that appear in s2 */
void squeeze(char s1[], const char s2[])
{
int i, j, k;
for (i = j = 0; s1[i] != '\0'; ++i) {
/* scan s2 looking for s1[i] */
for (k = 0; s2[k] != '\0' && s2[k] != s1[i]; ++k)
;
if (s2[k] == '\0') /* not found in s2 — keep it */
s1[j++] = s1[i];
}
s1[j] = '\0';
}
How It Works — Step by Step
Take s1 = "hello" and s2 = "aeiou":
- i=0, s1[i]=’h’ — inner loop scans
s2: ‘a’≠’h’, ‘e’≠’h’, ‘i’≠’h’, ‘o’≠’h’, ‘u’≠’h’, hits'\0'. Not ins2→s1[j++]='h'. - i=1, s1[i]=’e’ — inner loop: ‘a’≠’e’, ‘e’==’e’, stops.
s2[k]is'e', not'\0'→ found ins2, discard. - i=2, s1[i]=’l’ — not in
s2→ kept. - i=3, s1[i]=’l’ — not in
s2→ kept. - i=4, s1[i]=’o’ — found in
s2→ discarded. - After loop:
s1[j] = '\0'terminates the compacted string →"hll".
The two write-heads (i advancing unconditionally, j advancing only on a keep) compact the array in place without any extra buffer. This is the classic read/write pointer idiom for in-place filtering of arrays.
Compile and Run
gcc -ansi -Wall ex2-4.c -o ex2-4
./ex2-4
Sample Output
Before: hello, world! After: hll, wrld! Before: programming After: rorai
What This Exercise Teaches
- Two-index in-place filtering: using a read index
iand a write indexjto compact an array without extra memory — a pattern that appears everywhere in C string and array processing. - Loop-then-test search idiom: letting the inner loop run to exhaustion, then checking why it stopped. If
s2[k] == '\0', the character was absent; ifs2[k] == s1[i], it was found. This is exactly howstrchrworks internally. - Generalising single-argument to multi-argument: the only structural change from the original
squeeze(s, c)is wrapping the comparison in a loop overs2. Spotting that the outer shell stays the same while the predicate changes is a key design skill. - Null-terminating after compaction:
s1[j] = '\0'is not optional — without it the string retains stale characters past its logical end and produces undefined behaviour when passed to any string function.
Relation to the Standard Library
What squeeze does manually, the standard library approximates through two functions declared in <string.h>:
strchr(s, c)— searchessfor a single characterc; returns a pointer to it orNULL.strpbrk(s1, s2)— returns a pointer to the first character ins1that also appears anywhere ins2, orNULL.
You could rewrite the inner loop as if (!strchr(s2, s1[i])), or advance i through the string using strpbrk. The manual version shown above makes the mechanics explicit, which is exactly what K&R intends at this stage of the book.
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:
- Install GCC on Windows 11
- Install GCC on macOS
- Install GCC on Ubuntu/Linux
- VS Code for C Programming — recommended editor
← Exercise 2-3 |
Chapter 2 Solutions |
Exercise 2-5 →
Book:
The C Programming Language, 2nd Ed — Kernighan & Ritchie