Step 10 of 10
Challenge: squeeze out spaces
Another two-pointer classic, with both pointers moving in the same direction at different speeds:
- A read pointer visits every character.
- A write pointer marks where the next character we keep should go. It only advances when something is kept.
Because the write pointer never gets ahead of the read pointer, you can filter a string in place, in the same buffer, without allocating anything.
#include <stdio.h>
void keep_digits(char *s) {
char *write = s;
for (const char *read = s; *read != '\0'; read++) {
if (*read >= '0' && *read <= '9') {
*write = *read;
write++;
}
}
*write = '\0';
}
int main(void) {
char phone[] = "(555) 123-4567";
keep_digits(phone);
printf("%s\n", phone);
return 0;
}
5551234567
Trace a few steps
For "(555) 1": the read pointer sees (, which isn't kept, so write stays at index 0. Then 5, kept: written at index 0, write moves to 1. Then 5 to index 1, 5 to index 2. Then ) and the space are skipped, and 1 goes to index 3. The kept characters slide left over the ones that were dropped.
Don't forget the terminator
When the read pointer reaches the end, the characters after the write position are leftovers from the original string. Writing '\0' at the write position cuts them off. Forgetting it is the classic bug: the result would print with junk on the end.
phone is declared as an array (char phone[] = "..."), which makes a writable copy of the text. Modifying a string literal directly through a pointer would be undefined behavior.
Your turn: write void squeeze(char *s) that removes every space from s in place.