Editing a C String In-Place
21 Feb 2020
My least favorite part of a technical interview is the whiteboard exercise, in which yours truly has to stand up and try to come up with a solution to a non-trivial coding challenge while the interviewer(s) stare at my back and marvel at my illegible scribbles and frantic hand-waving.
I've never been able to solve any of these problems in the time allotted,
but I'm told the interviewers just want to know how I would reason my way
to a solution. I wonder, though, what they're really thinking when I can't
even get past main() {}
.
Recently, I was asked to write a function to edit a C string in-place with the goal of removing one or more occurrences of a specified character. So if the original string is "google" and 'g' is to be removed, the result will be "oole". I never reached the code-writing stage, but at least I was able to generate a function signature and babble about shifting characters to the left (which turned out to be what the interviewers were looking for, so I wasn't a complete noob):
void stredit_in_place(char* s, char rmch) { // Huh? }
When I got home, I decided I was going to fill in that function body even if it killed me. [1]
Left Shift
After many hours investigating methods for shifting chars to be kept on top of chars that need to be removed, I stumbled upon the following:
That left shift operation looked familiar, but I couldn't remember
the name of the relevant libc function until I poked around the man pages
and came across
memmove().
I knew this function needed to be enclosed in some sort of loop, and
eventually I came up with the following
(minus error checking
and casts involving ptrdiff_t
):
void stredit_in_place_ftw(char* s, char rmch) { char* starts = s; char* ends = s + strlen(s); while (1) { if (!(starts = strchr(starts, rmch))) { break; } memmove(starts, (starts + 1), (ends - starts)); } }
The loop body looks for the next matching rmch
char, and then
does the left shift, which we can get away with because memmove() knows how
to safely copy overlapping memory segments.
My algorithm
replaces every rmch
char with a left-shifted NUL char
so that the result
will always be a legal C string.
If there are no rmch
matches, then
strchr()
will visit every
char in the original string exactly once
until it reaches the trailing NUL char.
If all the chars are equal to rmch
,
then strchr() will always match the first char in the string until all
are replaced with NUL chars.
In fact, each of the chars in the original string will be visited
exactly once by strchr() no matter what.
Not bad for a noob.
Notes
Copyright © 2020 by Paul Eissen. Powered by w3.css