spinoza1111 said:
In the replace() program of last month's flame festival, a little
program was trying to get out. Here it is: an implementation of strstr
including a call that returns the offset of the found substring. Two
hours including all comments and dedicatory ode, written for this
occasion.
If I were going to put as much effort into writing comments as you
appear to have done with this program, I would explicitly discuss
the function's parameters and return value -- i.e., I would say
how the return value depends on the function's inputs and also
describe any side effects [*].
I wuv it: you see some effort, so you suggest something less useful as
an outlet for my energies. No, dear heart, a thousand times no.
I teach poetry, based on the Norton Anthology and John Lennard's The
Poetry Handbook. I note in my classes that there ain't no such thing
as free verse. Instead, a poet like TS Eliot and Ginsberg uses old
forms, and new forms, in new ways instead of trying to meet the
requirements of a traditional form.
In so doing, the poet sets up certain expectations which he either
meets or disappoints in the reader's first reading of the poem. When
he disappoints them, this means something. For example, Lennard shows
how a poem starts out like a sonnet and contains fourteen lines: but
some lines are fragmentary like a bombed city, since the sonnet is
about a Holocaust victim in a time when Adorno said we can't write any
more goddamn poetry.
Here, the comment block sets up the expectation that Nilges has
written some code and is gonna tell us, overall, what the code does.
So I do. Next, some but by no means all programs in the old days (when
programmers were more literate than today) would often contain a quote
AFTER the intro and BEFORE the code, in the same relative position a
dedicatory quote appears in a book, such as Shakespeare's First Folio,
which contains some dedicatory material AFTER the title page and
BEFORE the first play (which is for some silly reason the last
complete play of Shakespeare, The Tempest).
The reader is then either amused (if civilized and urbane) or outraged
(if like many programmers) but goes on to find, yes, functions without
my usual custom, which is to set up a visual fence as a line comment,
followed by the function name, followed by a statement as to what it
does, and yes indeedy, side effects...although great programmers make
fewer side effects.
But here, no such comments exist because
(1) If the code is small, let it document itself
(2) I would like to give the aliterate programmer-reader a break after
having him eyeball the ode.
You don't appear to have done this, and while based on your
comments I infer that the function returns a pointer to the
first occurrence of *strTarget in *strMaster, I have no idea
what the third parameter is for, and I don't really know what the
function does if the "target" is not a substring of the "master".
I can make a guess about the latter based on the behavior of the
standard-library function with the same name, but that's what it
is -- a guess.
No competent programmer expects commenting to tell her what the code
does. And simply reading the code would show you that the ptrIndex
parameter is needed when we want to get the offset of the string
without an extra calculation. Had you troubled to read the code, which
we must as programmers do whether or not there are comments, you would
find that strstrWithIndex and strstr are in a polymorphic relation to
each other in OO terms.
[*] The only case in which I would omit such discussion would be
when the names of the function and/or parameters are so descriptive
as to make discussion superfluous. In that regard, I find the
names used in the man-page documentation of strstr ("needle" and
"haystack") more descriptive if less formal than your "target"
and "master".
You've never taught English in China. It's offensive to people with
good English as a second language to use idioms in the cutesy way of
unix man pages.
Please don't credit me by name if you make changes based on the
above critique, or on the (half-hearted) one that follows the code.
I find this very offensive. But of course I won't.
#include <stdlib.h>
#include <stdio.h>
// ***************************************************************
// * *
// * strstr *
// * *
// * This function (strstr) finds a string, probably as fast as *
// * possible without extra memory usage over and above brute *
// * force. *
// * *
// * In searching a Nul terminated string for a substring, there *
// * are logically three possibilities in a left to right *
// * traversal of the master string that (1) looks for the *
// * first character of the target and then (2) matches all the *
// * remaining characters:
// * *
// * * (Erroneous): on the failure of a partial match, *
// * restart at the first nonmatching character. This is *
// * fast but wrong, since the matching string may *
// * overlap the partial match. *
// * *
// * * (Too slow): on the failure of a partial match, start*
// * one past the first character (of the partial match) *
// * *
// * * (Just right): while matching characters, note the *
// * leftmost character in the searched string, to the *
// * right of the first matched character, that matches *
// * both that character and, of course, the first *
// * character of the target. *
// * *
// * C H A N G E R E C O R D --------------------------------- *
// * DATE PROGRAMMER DESCRIPTION OF CHANGE *
// * -------- ---------- --------------------------------- *
// * 03 18 10 Nilges Version 1.0 *
// * *
// * ----------------------------------------------------------- *
// * *
// * To find a string, oh Muse! I sing, inside another String! *
// * Alternatives to me come in Three, ah, that's the thing: *
// * For the one thing for which the Wise must watch is mayhap, *
// * Partial occurences that most melancholy, overlap. *
// * The first is base, mechanical, low, and tragicomical: *
// * It's to restart from the previous beginning plus but One *
// * Oh what Mayhem to true Programming is thereby, done! *
// * But the job it will do, as did Hercules, *
// * His Labors for the Goddess cruel in Seneca's tragedies: *
// * Arduously and ignobly like unto the meanest Hind *
// * That knoweth not his Elbow from his Behind. *
// * The second is worse, a boner, a solecism, and a Seebach: *
// * The second restarts at the character that doth match! *
// * Oh muse! Such hellish Sights before me yawn: *
// * But be assur'd, 'tis darkest just before the Dawn. *
// * Shout for Victory, oh Thrace, and smite the Harp, and Grin: *
// * For lo, we start at the leftmost "handle" of the string *
// * When it occureth in *
// * The tragic partial match that hath failed us. *
// * If no such handle exists, then we can restart *
// * At the point of match failure: no, 'tis not a brain fart. *
// * Now we spy our magic bus: *
// * For this is the best Al Gore ithm *
// * That we can hope for in C, a language without Rhyme, or *
// * for that matter, Oh Muse! rhythm. *
// * *
// ***************************************************************
#define TRUTH -1
#define FALSITY 0
#define NULLITY 0
char * strstrWithIndex(char *strMaster,
char *strTarget,
int *ptrIndex)
{
char *ptrMaster = NULLITY;
char *ptrTarget = NULLITY;
char *ptrHandle = NULLITY;
int booFound = FALSITY;
if (!*strMaster || !*strTarget) return 0;
for (ptrMaster = strMaster; *ptrMaster
{
for (;
*ptrMaster && *ptrMaster != *strTarget;
ptrMaster++);
ptrTarget = strTarget;
*ptrIndex = ptrMaster - strMaster;
ptrHandle = 0;
for (;
*ptrTarget
?
(*ptrMaster
?
(*ptrMaster==*ptrTarget ? TRUTH : FALSITY)
:
FALSITY)
:
(booFound = TRUTH, FALSITY);
ptrMaster++, ptrTarget++)
{
if (ptrHandle = 0
&&
ptrMaster > strMaster
&&
*ptrMaster == *strTarget)
ptrHandle = ptrTarget;
}
if (booFound) return strMaster + *ptrIndex;
if (ptrHandle) ptrMaster = ptrHandle + 1;
}
*ptrIndex = 0;
return 0;
}
char * strstr(char *strMaster, char *strTarget)
{
int ptrIndex = 0;
return strstrWithIndex(strMaster, strTarget, &ptrIndex);
}
int main(void)
{
char *ptrIndex1 = NULLITY;
int intIndex1 = 0;
printf("strstr Simplified\n\n");
printf("Expect 0: %d\n", strstr("", ""));
printf("Expect 0: %d\n", strstr("0123456789", ""));
printf("Expect 0: %d\n", strstr("", "0"));
printf("Expect 0: %d\n", strstr("Here", "There"));
ptrIndex1 = strstrWithIndex("There", "here", &intIndex1);
printf("Expect 1: %d\n", intIndex1);
ptrIndex1 = strstrWithIndex("They seek him here",
"here",
&intIndex1);
printf("Expect 14: %d\n", intIndex1);
ptrIndex1 = strstrWithIndex("They seek him there",
"here",
&intIndex1);
printf("Expect 15: %d\n", intIndex1);
ptrIndex1 = strstrWithIndex
("The clc regs seek him everywhere",
"here",
&intIndex1);
printf("Expect 28: %d\n", intIndex1);
printf("Expect 'h': %c\n", *ptrIndex1);
ptrIndex1 = strstrWithIndex
("Is he in Heaven? Or in Hell?",
"?",
&intIndex1);
printf("Expect 15: %d\n", intIndex1);
printf("Expect '?': %c\n", *ptrIndex1);
ptrIndex1 = strstrWithIndex
("That damn'd elusive Spinoza won't tell!",
"Spinoza",
&intIndex1);
printf("Expect 20: %d\n", intIndex1);
printf("Expect 'p': %c\n", *(ptrIndex1+1));
printf("Expect '0': %c\n", *strstr("0123456789", "0"));
printf("Expect '1': %c\n", *strstr("0123456789", "1"));
printf("Expect '0': %c\n", *strstr("0123456789", "0"));
printf("Expect '9': %c\n", *strstr("0123456789", "9"));
printf("Expect '5': %c\n", *strstr("0123456789", "345") + 2);
printf("Expect '8': %c\n", *strstr("0123456789", "89"));
ptrIndex1 = strstrWithIndex("0123456789A89AB",
"89AB",
&intIndex1);
printf("Expect 11: %d\n", intIndex1);
return 0;
}
Still printing the output and asking the human to check it rather
than having the program check itself ....
Well, now that I think about it, I suppose that's not as bad as
it might be, since it would be easy enough -- in my preferred
development environment anyway [*] -- to copy the expected output
into a text file, capture actual output in another text file,
and have the computer compare the two.
[*] For short C programs -- text-based tools under Linux.