Efficency and the standard library

S

spinoza1111

[...]
That said, I do like the idiom
   size_t lenstr(char *string) {
           char *end = string;
           while (*end++)
                   ;
           return end - string;
   }
Not that it's likely to make a noticeable difference.  Or that it's likely
worth it when obviously the standard library one will be fine.

Note that ``end - string'' yields a value of type ptrdiff_t, a signed
type which very likely can't represent all values of type size_t.

This is unlikely to be an issue in practice.  On typical 32-bit
systems, problems show up only for strings longer than 2 gigabytes,
and even then the properties of 2's-complement arithmetic are likely
to result in the correct answer anyway.

But all this analysis, resulting in the conclusion that it will
almost certainly work properly, becomes unnecessary if you just
use strlen().

--
Keith Thompson (The_Other_Keith) (e-mail address removed)  <http://www.ghoti.net/~kst>
Nokia
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"

Kenny McCormack, thou should'st be here at this hour:
For Kiki is in finest Form, posting pompously and sour:
Exhibiting ersatz Learning, and utter Pedantry:
He concludes, after "all this analysis" that "almost certainly"
That "it" (Seebie's shit) will yeah right..."work properly".
But for "123" Seebie's code grinds out to the amazement of the Crowd
The number...the number...FOUR, to dismay that is loud.
Whilst we the putative Trolls do dance amidst burning Tyres
Laughing our hairy Asses off at the doom of Pedantry's pretentious
spires!
 
S

spinoza1111

You ran straight into the fencepost. And can we have more const,
pretty please?

He sure did. I was hoping as I went chronologically through the thread
to find someone who could find the bug before I woke up here in Asia,
but I posted my own correction before looking at replies to Seebie. It
looks like you may have, but you should have had the cojones to
describe the bug, taking the risk like a man that you may misdescribe
the bug. It's called Habermas' communicative reason and a common
search for TRUTH.
Phil, who uses strlen().

Sensible chap.

Ed, who uses C Sharp.
 
S

spinoza1111

I have no particular interest in this programming challenge,
though I do find some of the commentary amusing.  I thought it
might be of interest to do a code review.  The following is not
an endorsement or a condemnation of the code.  Rather it is an
informal account of code features that are problematic.

Notes on the Nilges code:

(1) At no point is there a comprehensive specification.  A fair
number of corner cases are left up in the air.  These include
overlapping targets, and empty targets.  There is no statement
of error handling strategy.  

(2) There are instances of failure to protect against
dereferencing null pointers.  Thus in function strLength the for
loop will dereference a null pointer if argument strInstring is
a null pointer.  Similarly function replace checks strTarget but
not strMaster.  ptrIndex1 is initialized to strMaster.  The
while loop, while(*ptrIndex1), will dereference a null pointer
if strMaster is null.  

The test cases do not check for null arguments nor all instances
of empty strings.  

(3) The TESTER macro is cumbersome and should be replaced by a
function.  

(4) It would be better if the test cases were moved to a
separate file - the plan would be for the main function to read
the test cases from from the test cases file and then compare
the actual test results with the expected test results.  

(5) The comments are inadequate.  The existing comments read
more like coding notes written on the spur of the moment to
remind the coder about what was going on.  There is no statement
of the algorithm being used; the comments often reference
concepts that are not explained.  For example, there is no
precise definition of segment nor of handle.  

(6) The commenting format is not well chosen.  The comments
break into the code and vice versa.  

(7) The code author uses a bizarre, idiosyncratic, and long
winded variant of Hungarian notation.  It's his privilege.  
Unfortunately the long names used are not informative.  For
example, the ptrIndex* variables.  What on earth are they, and
what are their invariants?  The only way to know what they are
is play computer, walk through the code, and reconstruct what
the coder's intent was.  

Then there are the ptrSegmentStruct variables.  One has a suffix
of Starts, one of Prev, and one is without a suffix.  Since the
key idea of the implementation is to generate a linked list of
segments, each (except possibly the last) being terminated by
the target string, it turns out that the ptrSegmentStructStarts
refers to the list head, ptrSegmentStruct refers to the current
pointer into the list, and ptrSegmentStructPrev refers to the
previous pointer into the list.  Or perhaps not.  

(8) The scheme of allocating space for each segment is mildly
inefficient, but is much better than reallocing space for the
output string.  In any case it is doubtful that execution
efficiency is among the objectives of this exercise.  

(9) In some places the code is overly complex.  A case in point
is:

lngNewLength += ptrSegmentStruct->lngSegmentLength +
                (ptrIndex2 && !*ptrIndex2
                 ?
                 lngReplacementLength
                 :
                 0);

There are several other instances of unnecessary complexity.  
The updating of the never defined Index variables is a case in
point.  

(10) Only one of strNew, strNewStart is needed.

(11) In conclusion, it is difficult to determine whether the
code works correctly because the design is not spelled out, the
variables are not properly documention, the testing framework is
inadequate, and the baroque nomeclature and coding complicate
analysis.  

Richard Harter, [email protected]://home.tiac.net/~cri,http://www.varinoma.com
Infinity is one of those things that keep philosophers busy when they
could be more profitably spending their time weeding their garden.

Looks great, and it looks like I need to review this carefully. I am
in my morning "pass" through many responses, including responses to
Seebach's latest brain fart. I will review your comments later.
 
S

spinoza1111

[...]
That said, I do like the idiom
size_t lenstr(char *string) {
char *end = string;
while (*end++)
;
return end - string;
}
Not that it's likely to make a noticeable difference.  Or that it's likely
worth it when obviously the standard library one will be fine.

I believe that you have a bug in that code Seebs. Perhaps you meant
something like this instead:
_____________________________________________________
size_t
xstrlen(char const* string)
{
    char const* end = string;
    while (*end) ++end;
    return end - string;}

_____________________________________________________

?

Good call, Chris.
 
S

spinoza1111

Extremely likely.

This is one of the reasons I rely on the standard library -- my success rate
in avoiding fencepost errors is slightly *less* than chance.  I'm not actually
very good at this stuff, which is why I spend so much time thinking about how
to do it better.

No argument there, none whatsoever. But lemme ask you a question.
Where the **** do you get off criticising people who are, if not
perfect, better than you? People like Schildt?

And why do suppose I started posting my own (vastly more challenging)
solution early when I knew it might have bugs, being self-confident
enough to risk exposure?

It's because REAL programming, as opposed to some bureaucratic job
finding other people's bugs, is humbling and challenging, and REAL
code review happens outside the language game of capitalism.

Read Habermas. And get a clue.
 
S

spinoza1111

I've looked at both. The first is easier on the eye, but I still can't
figure out what it does. You say, it finds the *next* occurence of the
target, why a loop then?


You can't really compare these (assuming they really do do the same thing);
your code uses some presumably tried and tested library function (strstr) to
do the tricky part, so you're comparing a *call* to that function to an
experimental *implementation* of it. That doesn't sound fair..

English public school rules apply to this fight, Bart: cf. Flashman's
savaging of Tom Brown in Tom Brown's Schooldays. Which is why it's so
much fun to win, as I am winning, despite Seebie's Flashman-like
behavior. He can't get a simple strlen replace right, yet dares to
attack my much more sophisticated and challenging solution and
Schildt.

I would prefer a Habermasian-civil structured walkthrough. However, we
live in a barbaric capitalism in which there are no holds barred. It's
Extreme Fighting. But:

Hasta la victoria siempre! - Ernesto Che Guevara

En cadenas vivir es vivir
En afrenta y oprobio sumido,
Del clarín escuchad el sonido;
¡A las armas, valientes, corred! - La Bayamesa
The efficiency varies. On my lccwin32 and DMC compilers, the time to find an
"A" string, in a string consisting entirely of As, seems to depend on the
length of the string it's searching (perhaps it's doing a strlen() first?).
On gcc it's instant.

(I came across the problem in a related function strchr(), in Malcolm's
Minibasic program, where it had the effect, on large input files, of slowing
down the interpreter from 80K lines per second to about 2K. Replacing the
strchr() call with one line of custom code (I think it was just looking for
next EOL), fixed that.)

Sounds like you have real applied comp sci chops.
 
S

spinoza1111

The humility is a good touch. You can use mine.

No, it is not. It is the humility of Dickens' Uriah Heep, for it is an
"humility" unlinked to the charitable willingness to REFRAIN from
posting unwarranted attacks on Schildt and others, an "humility"
linked instead to utter malice, directed at what Seebie considers safe
targets.

Dijkstra's essay "The Humble Programmer" was in my direct experience
misused. It was transformed into a call on programmers to be
subservient to corporate authority right at the end of the Sixties,
when the authority of property was in question world-wide. But
Dijkstra meant nothing of the sort.
 
S

spinoza1111

Because it finds the next occurrence repeatedly until there's no more.


I think it's extremely fair, because it highlights the flaw in his "I
refuse to use the library functions" attitude.

This is a false caricature. Were I to use C, I'd use what library
functions were safe. But I would create my own string library.

However, the corporate language game is to transform responsible adult
thought into a childish "attitude".

So, I have a Bad Attitude. I actually want to do a good job. Quite
frankly, based on my thirty years I don't think you do, in a
standalone, independent sense, anything like a good job in your chosen
profession, but this doesn't matter. Managers design organizations so
that errors are hopefully factored out, and in the social machine so
created, a person who can by himself do a complete good job is in fact
a "square peg in a round hole".

However, this reality is concealed from today's programmers, owing to
the fact that capitalism is a basically inhuman system despite its
good parts. People want to be *homo faber*, man the toolmaker, and
they don't want to do a small piece of a job only to see their work
corrected and criticised by people who can't themselves do the same
work.

Therefore a Pop culture pervades in programming shops: the delusion
that each male member (where the shop must usually exclude women in
order for the illusion to work) is "rilly" a proud and independent
professional when in fact he's the type of programmer who can't get a
strlen right, finds well-formatted code "unreadable" simply by virtue
of the pains taken by the formatter, the merest thought of which makes
our boy's butt hurt in that it's a reminder of a lost humanity, and
who finds correct grammar of complexity > low n "verbose".
Agreed that there are cases where there's reasons not to do that.

"There are", not "there's", Grammar Guy.
 
S

spinoza1111

OK, I implemented and tested (in about 25 minutes if you want to know)
the above-described solution to the "showstopper performance bug" that
Seebach more or less found.

This was the creation of many zero-length TYPsegmentstruct occurrences
when there are multiple adjacent hits. This code implements the plan
above.

The same cautions (make sure your browser doesn't split two lines, the
TESTER header and the final printf, at position 67 or whatever: make
sure it doesn't add a blank to the end of the TESTER macro
continuation lines) apply.

As before, a complete regression test is included.

"Oh yes. In Europe a much larger fraction of the population can write.
People in America have really suffered from the combination of TV,
which makes reading superfluous, and the telephone. A few years ago I
was at CalTech and that is a hiqh quality place and everybody
recommends it because the students are so bright. A graduate confessed
to me—no he did not confess, he just stated it, that he did not care
about his writing, since he was preparing himself for an industrial
career. Poor industry!" - Edsger Dijkstra, 1985

"You talk like a fag, and you're shit's all fucked up." - Idiocracy,
Mike Judge, 2005



// ***************************************************************
// * *
// * replace() demo *
// * *
// * Demonstrates how to replace non-NUL-defined strings in C *
// * using a simple function, and bypassing string.h. *
// * *
// * C H A N G E R E C O R D --------------------------------- *
// * DATE PROGRAMMER DESCRIPTION OF CHANGE *
// * -------- ---------- --------------------------------- *
// * 02 07 10 Nilges Version 1.0 *
// * *
// * 02 07 10 Nilges Bug: partial matches not handled *
// * correctly: need to iterate search *
// * for match. *
// * *
// * 02 07 10 Nilges 1. Santosh suggested tests *
// * 2. Heathfield put the boot in re *
// * including malloc *
// * *
// * 02 07 10 Nilges 1. Remove string.h use and code *
// * strlen by hand *
// * 2. Add comment block and comments*
// * inline. *
// * 3. free() storage *
// * 4. Use macro for testing *
// * 5. Bug: calculation of *
// * lngNewLength used incorrect *
// * index (intIndex3 instead of 2)*
// * which caused a memory leak. *
// * *
// * 02 07 10 Nilges 1. Bug: Ike Naar test failed. *
// * At end of scan loop, main *
// * string pointer was not *
// * correctly updated from index3 *
// * *
// * 02 07 10 Nilges Added new Santosh test *
// * *
// * 02 07 10 Nilges Added new Ike Naar test *
// * *
// * 02 08 10 Nilges 1. Added some new comments *
// * 2. Make "check for a complete *
// * match "structured" by means *
// * of a tested assignment *
// * 3. Get rid of "replace at end" *
// * evilness: the only time this *
// * flag is meaningful is in the *
// * LAST segment. *
// * 4. Return replace count *
// * 5. TESTER macro assertion added *
// * *
// * 02 10 10 Nilges 1. Bug fix: in a partial match, *
// * the main scan index is set to *
// * one past the end, which misses*
// * full matches that start *
// * between the first character of*
// * the partial match and its end.*
// * *
// * No longer updating the main *
// * scan index (ptrIndex1) to the *
// * point of partial match *
// * failure: setting it one past *
// * the first character of the *
// * partial match. *
// * *
// * 2. Line up expected & actual *
// * results per excellent *
// * suggestion (who made this?) *
// * *
// * 3. After a partial match, update *
// * the main handle search index *
// * (ptrIndex1) to the first *
// * occurrence of the handle *
// * character after the start of *
// * the partial match, or to the *
// * index of the unmatched char. *
// * *
// * 021310 Nilges Bug: failed to handle a one-char *
// * replace (of a by x in b) since *
// * we set ptrIndex2 to point to NUL *
// * which made it appear that there *
// * was a match. When the main index *
// * to the master string (ptrIndex1) *
// * goes off the end of a cliff, we *
// * needed to break out of the search *
// * loop. *
// * *
// * This also entailed setting the *
// * target index ptrIndex2 to 0 at the*
// * beginning of each search so that *
// * it is not erroneously used to *
// * indicate that there's an insert *
// * needed at the end. *
// * *
// * I have also added additional tests*
// * to verify that the code works *
// * when the string and target end *
// * at the same time. *
// * *
// * 02 14 10 Nilges This version detects zero length *
// * segments and merges them *
// * ----------------------------------------------------------- *
// * *
// * "In the near future we shall have to live with the *
// * superstition that programming is 'so easy that even a *
// * Republican can do it!'" *
// * *
// * - E. W. Dijkstra *
// * *
// * *
// ***************************************************************
#include <stdio.h>
#include <stdlib.h>

// ***** Segmentation *****
struct TYPsegmentstruct
{ char * strSegment;
long lngSegmentLength;
struct TYPsegmentstruct * ptrNext; };

// ---------------------------------------------------------------
// Calculate string length
//
//
long strLength(char *strInstring)
{
char *ptrInstring;
for (ptrInstring = strInstring; *ptrInstring; ptrInstring++);
return ptrInstring - strInstring;
}

// ---------------------------------------------------------------
// Replace target by replacement string in master string
//
//
// Caution: the string returned by this function should be freed.
//
//
char * replace(char * strMaster,
char * strTarget,
char * strReplacement,
long * ptrReplacements)
{
char * ptrIndex0;
char * ptrIndex1;
char * ptrIndex2;
char * ptrIndex3;
char * ptrIndex4;
char * strNew;
char * strNewStart;
long lngNewLength;
long lngCount;
long lngReplacementLength;
struct TYPsegmentstruct * ptrSegmentStructStarts;
struct TYPsegmentstruct * ptrSegmentStruct;
struct TYPsegmentstruct * ptrSegmentStructPrev;
lngReplacementLength = strLength(strReplacement);
if (!*strTarget)
{
printf("Error in calling replace(): target can't be null");
abort();
}
ptrIndex1 = strMaster;
ptrSegmentStruct = 0;
ptrSegmentStructPrev = 0;
lngNewLength = 0;
*ptrReplacements = 0;
while(*ptrIndex1)
{
ptrIndex0 = ptrIndex1;
ptrIndex2 = 0;
while (-1)
{
// --- Check for (one character) handle
for(;
*ptrIndex1 && *ptrIndex1 != *strTarget;
ptrIndex1++);
if (!*ptrIndex1) break;
// --- Check for complete match while remembering the
// --- last position of the handle
ptrIndex4 = 0;
for(ptrIndex2 = strTarget + 1,
ptrIndex3 = ptrIndex1 + 1;
*ptrIndex3
&&
*ptrIndex2
&&
*ptrIndex3 == *ptrIndex2;
ptrIndex3++, ptrIndex2++)
{
if (*ptrIndex3 == *strTarget
&&
ptrIndex4 == 0) ptrIndex4 = ptrIndex3;
}
// End test: check complete match, update main ptr past
// partial match while checking for end of loop
if ((!*ptrIndex2 ? ((*ptrReplacements)++, -1) : 0)
||
(!*ptrIndex3 ? (ptrIndex1 = ptrIndex3, -1) : 0))
break;
// Update the main search pointer
ptrIndex1 = (ptrIndex4 == 0 ? ptrIndex3 : ptrIndex4);
}
// --- Create new segment
if (ptrSegmentStruct != 0
&&
ptrSegmentStruct->lngSegmentLength <= 0
&&
ptrIndex1 == ptrIndex0)
{
// We don't want to create a lot of null segments
ptrSegmentStruct->lngSegmentLength--;
}
else
{
if (!(ptrSegmentStruct =
malloc(sizeof(struct TYPsegmentstruct))))
abort();
ptrSegmentStruct->strSegment = ptrIndex0;
ptrSegmentStruct->lngSegmentLength =
ptrIndex1 - ptrIndex0;
ptrSegmentStruct->ptrNext = 0;
if (ptrSegmentStructPrev != 0)
ptrSegmentStructPrev->ptrNext = ptrSegmentStruct;
else
ptrSegmentStructStarts = ptrSegmentStruct;
ptrSegmentStructPrev = ptrSegmentStruct;
}
// --- Update mallocation length
lngNewLength += (ptrSegmentStruct->lngSegmentLength <= 0
?
0
:
ptrSegmentStruct->lngSegmentLength)
+
(ptrIndex2 && !*ptrIndex2
?
lngReplacementLength
:
0);
// --- Get past end of target string & iterate
if (*ptrIndex1) ptrIndex1 = ptrIndex3;
}
// --- Allocate just enough storage for the new string
if (!(strNewStart = malloc(lngNewLength + 1))) abort();
// --- Build the new string whilst freeing the list
strNew = strNewStart;
ptrSegmentStruct = ptrSegmentStructStarts;
while (ptrSegmentStruct)
{
for (ptrIndex1 = ptrSegmentStruct->strSegment,
lngCount = 0;
lngCount < ptrSegmentStruct->lngSegmentLength;
ptrIndex1++, lngCount++, strNew++)
*strNew = *ptrIndex1;
if (ptrSegmentStruct->ptrNext
||
ptrIndex2 != 0 && !*ptrIndex2)
for (lngCount =
(ptrSegmentStruct->lngSegmentLength
>
0
?
1
:
-(ptrSegmentStruct->lngSegmentLength) + 1);
lngCount > 0;
lngCount--)
for (ptrIndex1 = strReplacement;
*ptrIndex1;
ptrIndex1++, ++strNew)
*strNew = *ptrIndex1;
ptrSegmentStructPrev = ptrSegmentStruct;
ptrSegmentStruct = ptrSegmentStruct->ptrNext;
free(ptrSegmentStructPrev);
}
*strNew = '\0';
return strNewStart;
}

// ---------------------------------------------------------------
// Statement-format test macro
//
//
#define TESTER(resultPtr, master, target, replacement, expected,
expectedReplacements, replacements) \
{ \
printf("Replace \"%s\" by \"%s\" in \"%s\"\n", \
(target), (replacement), (master)); \
printf("Expect \"%s\":\n \"%s\"\n", \
(expected), \
resultPtr = replace((master), \
(target), \
(replacement), \
&(replacements))); \
printf("Replacements expected: %d: replacements: %d\n", \
(expectedReplacements), \
(replacements)); \
if (!(strLength(resultPtr) \
== \
strLength(master) \
+ \
(strLength(replacement)-strLength(target)) \
* \
replacements)) \
printf("Assertion failed\n"); \
printf("\n\n"); \
free(resultPtr); \
}

// ---------------------------------------------------------------
// Main procedure
//
//
int main()
{
char *ptrResult;
long lngReplacements;
printf("\nReplace\n\n\n");
TESTER(ptrResult,
"xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"x",
"y",
"yyyyyyyyyyyyyyyyyyyyyyyyyyyy",
28,
lngReplacements)
TESTER(ptrResult,
"1111123bbb1111123bbb11123bb11111231111112111111123",
"111123",
"ono",
"1onobbb1onobbb11123bb1ono1111112111ono",
4,
lngReplacements)
TESTER(ptrResult,
"bbb1111123bbbbb",
"111123",
"ono",
"bbb1onobbbbb",
1,
lngReplacements)
TESTER(ptrResult,
"a stupid error",
"stupid error",
"miracle",
"a miracle",
1,
lngReplacements)
TESTER(ptrResult,
"a stupid error",
"stupid",
"miracle",
"a miracle error",
1,
lngReplacements)
TESTER(ptrResult,
"the stupid error",
"the stupid error",
"a miracle",
"a miracle",
1,
lngReplacements)
TESTER(ptrResult,
"the miracle",
"the",
"a",
"a miracle",
1,
lngReplacements)
TESTER(ptrResult,
"a miraclsnirpKamunkle",
"snirpKamunkle",
"e",
"a miracle",
1,
lngReplacements)
TESTER(ptrResult,
"a miraclesnirpKamunkle",
"a miracle",
"",
"snirpKamunkle",
1,
lngReplacements)
TESTER(ptrResult,
" a miraclesnirpKamunkle",
"a miracle",
"",
" snirpKamunkle",
1,
lngReplacements)
TESTER(ptrResult,
" a miraclesnirpKamunklea miraclea miracle",
"a miracle",
"",
" snirpKamunkle",
3,
lngReplacements)
TESTER(ptrResult,
"a miracle a miraclesnirpKamunkle a Miraclea
miracleamiracle",
"a miracle",
"",
" snirpKamunkle a Miracle",
3,
lngReplacements)
TESTER(ptrResult,
"a stupid errord",
"stupid error",
"miracle",
"a miracled",
1,
lngReplacements)
TESTER(ptrResult,
"a stupid errod",
"stupid error",
"miracle",
"a stupid errod",
0,
lngReplacements)
TESTER(ptrResult,
"a sstupid error",
"stupid error",
"miracle",
"a smiracle",
1,
lngReplacements)
TESTER(ptrResult,
"a stupid errorstupid error",
"stupid error",
"miracle",
"a miraclemiracle",
2,
lngReplacements)
TESTER(ptrResult,
"a stupid error stupiderror",
"stupid error",
"miracle",
"a miracle stupiderror",
1,
lngReplacements)
TESTER(ptrResult,
"bbbbbbbbbb",
"b",
"a",
"aaaaaaaaaa",
10,
lngReplacements)
TESTER(ptrResult,
"In the halls of R'yleh great %s lies dreaming",
"%s",
"Cthulu",
"In the halls of R'yleh great Cthulu lies dreaming",
1,
lngReplacements)
TESTER(ptrResult,
"%s%s%s%s%s%s",
"%s",
"Cthulu",
"CthuluCthuluCthuluCthuluCthuluCthulu",
6,
lngReplacements)
TESTER(ptrResult,
"banana",
"ana",
"oat",
"boatna",
1,
lngReplacements)
TESTER(ptrResult,
" a stupid errorstupid errorHeystupid errors",
"stupid error",
"+",
" a ++Hey+s",
3,
lngReplacements)
TESTER(ptrResult,
"foo barfoo barf",
"foo bar",
"bas",
"basbasf",
2,
lngReplacements)
TESTER(ptrResult,
"abab",
"ba",
"ba",
"abab",
1,
lngReplacements)
TESTER(ptrResult,
"abab",
"bab",
"boop",
"aboop",
1,
lngReplacements)
TESTER(ptrResult,
"banana",
"ana",
"ono",
"bonona",
1,
lngReplacements)
TESTER(ptrResult,
"a",
"x",
"b",
"a",
0,
lngReplacements)
TESTER(ptrResult,
"x",
"x",
"b",
"b",
1,
lngReplacements)
TESTER(ptrResult,
"egregious",
"egregious",
"egregious",
"egregious",
1,
lngReplacements)
TESTER(ptrResult,
"egregious",
"egregious",
"x",
"x",
1,
lngReplacements)
printf("\n\nTesting complete: check output carefully: \"Assertion
failed\" should not occur!\n\n");
return 0;
}


Replace


Replace "x" by "y" in "xxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Expect "yyyyyyyyyyyyyyyyyyyyyyyyyyyy":
"yyyyyyyyyyyyyyyyyyyyyyyyyyyy"
Replacements expected: 28: replacements: 28


Replace "111123" by "ono" in
"1111123bbb1111123bbb11123bb11111231111112111111123"
Expect "1onobbb1onobbb11123bb1ono1111112111ono":
"1onobbb1onobbb11123bb1ono1111112111ono"
Replacements expected: 4: replacements: 4


Replace "111123" by "ono" in "bbb1111123bbbbb"
Expect "bbb1onobbbbb":
"bbb1onobbbbb"
Replacements expected: 1: replacements: 1


Replace "stupid error" by "miracle" in "a stupid error"
Expect "a miracle":
"a miracle"
Replacements expected: 1: replacements: 1


Replace "stupid" by "miracle" in "a stupid error"
Expect "a miracle error":
"a miracle error"
Replacements expected: 1: replacements: 1


Replace "the stupid error" by "a miracle" in "the stupid error"
Expect "a miracle":
"a miracle"
Replacements expected: 1: replacements: 1


Replace "the" by "a" in "the miracle"
Expect "a miracle":
"a miracle"
Replacements expected: 1: replacements: 1


Replace "snirpKamunkle" by "e" in "a miraclsnirpKamunkle"
Expect "a miracle":
"a miracle"
Replacements expected: 1: replacements: 1


Replace "a miracle" by "" in "a miraclesnirpKamunkle"
Expect "snirpKamunkle":
"snirpKamunkle"
Replacements expected: 1: replacements: 1


Replace "a miracle" by "" in " a miraclesnirpKamunkle"
Expect " snirpKamunkle":
" snirpKamunkle"
Replacements expected: 1: replacements: 1


Replace "a miracle" by "" in " a miraclesnirpKamunklea miraclea
miracle"
Expect " snirpKamunkle":
" snirpKamunkle"
Replacements expected: 3: replacements: 3


Replace "a miracle" by "" in "a miracle a miraclesnirpKamunkle a
Miraclea miracleamiracle"
Expect " snirpKamunkle a Miracle":
" snirpKamunkle a Miracleamiracle"
Replacements expected: 3: replacements: 3


Replace "stupid error" by "miracle" in "a stupid errord"
Expect "a miracled":
"a miracled"
Replacements expected: 1: replacements: 1


Replace "stupid error" by "miracle" in "a stupid errod"
Expect "a stupid errod":
"a stupid errod"
Replacements expected: 0: replacements: 0


Replace "stupid error" by "miracle" in "a sstupid error"
Expect "a smiracle":
"a smiracle"
Replacements expected: 1: replacements: 1


Replace "stupid error" by "miracle" in "a stupid errorstupid error"
Expect "a miraclemiracle":
"a miraclemiracle"
Replacements expected: 2: replacements: 2


Replace "stupid error" by "miracle" in "a stupid error stupiderror"
Expect "a miracle stupiderror":
"a miracle stupiderror"
Replacements expected: 1: replacements: 1


Replace "b" by "a" in "bbbbbbbbbb"
Expect "aaaaaaaaaa":
"aaaaaaaaaa"
Replacements expected: 10: replacements: 10


Replace "%s" by "Cthulu" in "In the halls of R'yleh great %s lies
dreaming"
Expect "In the halls of R'yleh great Cthulu lies dreaming":
"In the halls of R'yleh great Cthulu lies dreaming"
Replacements expected: 1: replacements: 1


Replace "%s" by "Cthulu" in "%s%s%s%s%s%s"
Expect "CthuluCthuluCthuluCthuluCthuluCthulu":
"CthuluCthuluCthuluCthuluCthuluCthulu"
Replacements expected: 6: replacements: 6


Replace "ana" by "oat" in "banana"
Expect "boatna":
"boatna"
Replacements expected: 1: replacements: 1


Replace "stupid error" by "+" in " a stupid errorstupid errorHeystupid
errors"
Expect " a ++Hey+s":
" a ++Hey+s"
Replacements expected: 3: replacements: 3


Replace "foo bar" by "bas" in "foo barfoo barf"
Expect "basbasf":
"basbasf"
Replacements expected: 2: replacements: 2


Replace "ba" by "ba" in "abab"
Expect "abab":
"abab"
Replacements expected: 1: replacements: 1


Replace "bab" by "boop" in "abab"
Expect "aboop":
"aboop"
Replacements expected: 1: replacements: 1


Replace "ana" by "ono" in "banana"
Expect "bonona":
"bonona"
Replacements expected: 1: replacements: 1


Replace "x" by "b" in "a"
Expect "a":
"a"
Replacements expected: 0: replacements: 0


Replace "x" by "b" in "x"
Expect "b":
"b"
Replacements expected: 1: replacements: 1


Replace "egregious" by "egregious" in "egregious"
Expect "egregious":
"egregious"
Replacements expected: 1: replacements: 1


Replace "egregious" by "x" in "egregious"
Expect "x":
"x"
Replacements expected: 1: replacements: 1




Testing complete: check output carefully: "Assertion failed" should
not occur!
 
S

spinoza1111

Yes Fred, it is. Note it is null pointer safe. Anything else?

While it appears to work, it has a showstopper of an error in style,
Joe. This is the use of "l" to mean "length" when in common fonts l
and 1 (the famous number) are different by only one pixel.

Hard to read, even if you can read, as opposed to the "unreadability"
of the aliterate.

But hey, what do I know. I write like a fag, and my shit's all fucked
up, right? Right...
 
S

spinoza1111

Looks great, and it looks like I need to review this carefully. I am
in my morning "pass" through many responses, including responses to
Seebach's latest brain fart. I will review your comments later.

Naw, on first reading, it don't look that great: a lot of pompous
windbaggery in the corporate genre. But I need to go out for a run
before I start torturing quite small animals. I will blow this out of
the water later.
 
S

Seebs

Everybody makes stupid mistakes.

I make them more than most people. As a compensating tactic, I can be pretty
careful about working things out and testing them... But I tend not to when
posting to Usenet (although I always check my facts before posting nonsense
to Usenet!).
When professionals make stupid mistakes (and
yes, they do), they don't try to make the situation worse by denying or
covering up the mistake.

In general, no. Someone pointed that one out, and I concede cheerfully that,
yes, that's a pretty stupid mistake. I make stupid mistakes a *lot*, so I'm
used to that. Note that I make them a lot less often on much more
complicated things than on simpler things; a neat quirk of brain chemistry
or something. And I don't just mean "less often, compared to other people"; I
mean less often in absolute terms. I'm much more likely to get something
trivial wrong than something interesting and challenging.
Schildt's mistake, and it's one which he has
yet to acknowledge as far as I am aware, is that he has failed to
produce a comprehensive errata list for his C books.

I disagree. The problem is not the lack of an errata list; it's that he
still doesn't even *understand* how feof() works. He's written a series
of Pascal books which have been cleverly relabeled "C" and had some of the
punctuation altered, in effect. He got several of the "easy" mistakes that
were, say, posted on my page, fixed for the 4th edition. He didn't fix the
much more serious logic flaws introduced by his unwillingness to comprehend
how end-of-file conditions are handled in C.

And that's the thing. Errata would be one thing. But if every example I
read using feof() used it incorrectly, and multiple examples of how to do
input loops used feof() incorrectly, that suggests to me that these are not
merely "stupid mistakes" (fencepost errors, typos, etcetera), but a genuine
failure to comprehend something which I think can be reasonably regarded as
fairly basic.

-s
 
S

spinoza1111

"spinoza1111" ha scritto nel messaggio...code...

    TESTER(ptrResult,
           "a miracle a miraclesnirpKamunkle a Miraclea
miracleamiracle",
           "a miracle",
           "",
           " snirpKamunkle a Miracle",
           4,
           lngReplacements)

i think it should be:

TESTER(ptrResult,
           "a miracle a miraclesnirpKamunkle a Miraclea
miraclea miracle",
^^^^^^^^^^^^^^^^^^
           "a miracle",
           "",
           " snirpKamunkle a Miracle",
           4,
           lngReplacements)
For the problem; i wrote the routine for doing that
in assembly using in that routine no string.h function

Thanks for your contributions, but:

(1) I am not qualified to read assembler (note that that's how a
gentlemen speaks when he is not qualified to read code: he doesn't
call the code unreadable)

(2) The problem was to be solved in C
 
S

spinoza1111

I make them more than most people.  As a compensating tactic, I can be pretty
careful about working things out and testing them...  But I tend not to when
posting to Usenet (although I always check my facts before posting nonsense
to Usenet!).


In general, no.  Someone pointed that one out, and I concede cheerfully that,
yes, that's a pretty stupid mistake.  I make stupid mistakes a *lot*, so I'm
used to that.  Note that I make them a lot less often on much more
complicated things than on simpler things; a neat quirk of brain chemistry
or something.  And I don't just mean "less often, compared to other people"; I
mean less often in absolute terms.  I'm much more likely to get something
trivial wrong than something interesting and challenging.

Why are you so self-centered? We're really not very interested in your
brain chemistry. The problem is the effect of your malicious and self-
serving behavior on others.
I disagree.  The problem is not the lack of an errata list; it's that he
still doesn't even *understand* how feof() works.  He's written a series
of Pascal books which have been cleverly relabeled "C" and had some of the
punctuation altered, in effect.  He got several of the "easy" mistakes that
were, say, posted on my page, fixed for the 4th edition.  He didn't fix the
much more serious logic flaws introduced by his unwillingness to comprehend
how end-of-file conditions are handled in C.

Given your failures to comprehend issues and simple mistakes, you're
without standing to write this paragraph. Part of the purpose of C was
to enable a "pascal" style in that it was supposed to be a safer
language than PL/I.
 
S

spinoza1111

I have no particular interest in this programming challenge,
though I do find some of the commentary amusing.  I thought it
might be of interest to do a code review.  The following is not
an endorsement or a condemnation of the code.  Rather it is an
informal account of code features that are problematic.

Notes on the Nilges code:

(1) At no point is there a comprehensive specification.  A fair
number of corner cases are left up in the air.  These include
overlapping targets, and empty targets.  There is no statement
of error handling strategy.  

If you mean in the code, this is FALSE. These issues were handled and
they were discussed. RTFT

And since when was a "comprehensive specification" required in the
documentation? No other code even comes close to the utility and
completeness of the comments in this code. Sure, they could be
improved: but do note that any actual improvements would make the
documentation less "readable" using the demotic (and quite ignorant)
definition of "readability" used by many posters here.
(2) There are instances of failure to protect against
dereferencing null pointers.  Thus in function strLength the for
loop will dereference a null pointer if argument strInstring is
a null pointer.  Similarly function replace checks strTarget but
not strMaster.  ptrIndex1 is initialized to strMaster.  The
while loop, while(*ptrIndex1), will dereference a null pointer
if strMaster is null.  

This is correct. But note that you're subjecting the code to a more
exacting standard that any other competitor meets, or for that matter
99% of C programs (which typically will fail if passed a null
function), out of personal malice, animosity, and envy...of the fact
that I can do two things seldom mastered simultaneously: write like a
humanist and code better than you.

Seriously, how many times have you checked for a NULL parameter
explicitly?

This issue is fabricated. Even quality library programs don't compare
to NULL; instead, a failure occurs inside the library code. It's
arguably a good practice, but its implementation in my code needs a
more general strategy for handling errors.

Your goal is "destroy Nilges, because he can do our job and the guy
doesn't even know C! He can also write a complex sentence! Nilges must
die!"

The test cases do not check for null arguments nor all instances
of empty strings.  

Twenty lashes with a wet noodle.

Clown.

OK, so code them in the idioms supported and post them, and I will add
them. What part of collaboration don't you understand?
(3) The TESTER macro is cumbersome and should be replaced by a
function.  

It is no more cumbersome than the lumber in your brain. I'm tired of
little coding monkeys who cover up their lack of energy with big words
used unconsciously-metaphorically.

However, it could I suppose be a function as I scale up.
(4) It would be better if the test cases were moved to a
separate file - the plan would be for the main function to read
the test cases from from the test cases file and then compare
the actual test results with the expected test results.  

The test software shouldn't become the main focus. It should be
simple, otherwise we get into an infinite regress.
(5) The comments are inadequate.  The existing comments read
more like coding notes written on the spur of the moment to
remind the coder about what was going on.  There is no statement
of the algorithm being used; the comments often reference
concepts that are not explained.  For example, there is no
precise definition of segment nor of handle.  

If you mean, in "read like coding notes", the change record, that is
what they are. I don't cover up my bugs, nor grin about them like
Seebie. As for the remainder, I mean to generate software by writing
first, coding later, and providing an audit trail. Of course, the
comments could and should be cleaned up were I to publish the code,
but again: you invent ad-hoc criteria, meant to be applied ONLY to
this code, out of adversarial hatred, envy and malice. In a court of
law, you'd be in contempt.
(6) The commenting format is not well chosen.  The comments
break into the code and vice versa.
Incoherent. 

(7) The code author uses a bizarre, idiosyncratic, and long
winded variant of Hungarian notation.  It's his privilege.  

Damn straight. I am the King of Hungary.
Unfortunately the long names used are not informative.  For
example, the ptrIndex* variables.  What on earth are they, and
what are their invariants?  The only way to know what they are
is play computer, walk through the code, and reconstruct what
the coder's intent was.  

No, it just needs a read of the code. ptr is a pointer MEANT TO BE
MODIFIED, as opposed to str, which is a pointer to a char meant not to
be modified. Some C programmers in these threads would suggest const
for the latter, but others have discouraged its use.

You are in fact conducting the sort of "structured walkthru" that in
my experience appeared at Bell Northern Research after the election of
Reagan, one in which issues were fabricated ad-hoc out of hatred, envy
and malice because Northern Telecom executives (some of whom later
went to jail) were forcing different BNR sites to compete with each
other so they could get fat bonuses and live like swine...while former
members of the scientific staff at Mountain View die in motels without
health insurance.

I've already explained how easy it is for a competent tech, using a
modern era (or even emacs) to globally scan/replace ptrIndex1 to
index1, or whatever he wants. If I were coding in an office that
mandated in its standard manual, or as an oral rule, either "no
Hungarian" or "Szymonyi Hungarian" as opposed to my standard (which
happens to have been invented inside IBM when Charles Szymonyi was
failing to adjust to socialism, and which was stolen and modified by
him), I would use the office standard.

What part of "red herring" don't you understand?

Then there are the ptrSegmentStruct variables.  One has a suffix
of Starts, one of Prev, and one is without a suffix.  Since the

Wow. His shit's all fucked up.
key idea of the implementation is to generate a linked list of
segments, each (except possibly the last) being terminated by

OK, so far.
the target string, it turns out that the ptrSegmentStructStarts
refers to the list head, ptrSegmentStruct refers to the current
pointer into the list, and ptrSegmentStructPrev refers to the
previous pointer into the list.  Or perhaps not.  

Or perhaps not (and screw your irony). It's a perfectly meaningful
triad of names. We need to know the first entry (Starts) to assemble
the output string. We need to walk the structure with the unsuffixed
name. And the Prev pointer, which is inactive and unused after the
scan for target loop, is initialized correctly to zero so that the
append can be written properly:

if (ptrSegmentStructPrev != 0)
ptrSegmentStructPrev->ptrNext = ptrSegmentStruct;
else
ptrSegmentStructStarts = ptrSegmentStruct;

The use of Prev is perfectly guarded in the above. Do you in fact know
how to construct a linked list (Heathfield can't)?

At some point in the distant past, Harter, you were able to write
competent code, for I saw an old 1990 program of yours that was
competent. I think you are now some sort of manager who is today
unable, unlike me, to crank this level of code in the time I
took...about two hours for the first version, and a total of 8..10
hours thereafter. I conclude that you are hand-waving and using
corporatese out of hatred, envy and malice. What's disturbing is that
the appearance of hatred, envy and malice in code reviews first
appeared in my experience on the job after Reagan was elected, and
companies made programmers into perpetual infants, always candidates
for their posts, whereas today, people air their hatred, envy and
malice recreationally and sadistically.

(8) The scheme of allocating space for each segment is mildly
inefficient, but is much better than reallocing space for the
output string.  In any case it is doubtful that execution
efficiency is among the objectives of this exercise.  

You are so full of hatred, envy and malice that you cannot be in the
slightest gracious about anything, can you. Instead, you fall into
neutral corporate prose.

At least you can spell "efficient".

Given the objectives, the only "inefficiency" was fixed this morning.
This was the generation of zero length segments.

As you seem to know, a realloc would involve to many memory copies,
unbounded apriori. Whereas the assembly of the final string takes M
mallocs for the segments (where M == the number of targets that are
not immediately preceded by > 1 targets) and one malloc for the final
string, and minimal motion of bytes to the new string.
(9) In some places the code is overly complex.  A case in point
is:

lngNewLength += ptrSegmentStruct->lngSegmentLength +
                (ptrIndex2 && !*ptrIndex2
                 ?
                 lngReplacementLength
                 :
                 0);

There are several other instances of unnecessary complexity.

What you mean is that there are no longer any programmers in fact
considerate enough of their intelligent readers to take the trouble to
so format code under the (rather severe) 67 character line limit
imposed by the newsreaders. Two-dimensional formatting in fact is a
great way to exhibit operator precedence.

It is true that one of these statements is munged in the current
edition of the code (and only one), but a competent technician knows
how to fix this based on the consistency of the style, a consistency
that appears to apes as unnecessary complexity.

You see, dear chap, what you mean by "unnecessary complexity" is in
fact any evidence of thought or work. Because data processing has
become a pure cost center, executives are troubled by evidence of
thought or work on the part of which has become a pure eunuch class,
charged with pure software maintenance and the chanting of hymns and
anthems to capitalism.

 
The updating of the never defined Index variables is a case in
point.  

(10) Only one of strNew, strNewStart is needed.

You don't know what you're talking about, and you have not diligently
or adequately studied the code. strNew is needed to index through the
new string, whereas we need to return strNewStart.

"Never defined Index variables" is gibberish.

In fine, although I expected better from you, you've Swift Boated the
code, creating a pompous document that will be used by subsequent
posters as "evidence". It's the same sort of document that Seebie used
to swift boat Schildt.

What a jerk!

(11) In conclusion, it is difficult to determine whether the
code works correctly because the design is not spelled out, the
variables are not properly documention, the testing framework is
inadequate, and the baroque nomeclature and coding complicate
analysis.  

Pompous, meaningless bullshit. For example, most corporate types who
use the word "baroque" couldn't identify Baroque music or art in a
simple test. Here, it means "my God, someone is thinking originally.
Kill him!"
 
M

Moi

While it appears to work, it has a showstopper of an error in style,
Joe. This is the use of "l" to mean "length" when in common fonts l and
1 (the famous number) are different by only one pixel.

Hard to read, even if you can read, as opposed to the "unreadability" of
the aliterate.

FTFY:

size_t Strlen(char *StrTheStringThatNeedsToBeMeasuredButWhomsNameCannotBeSpoken)
{
size_t SizTheLengthOfTheStringThatNeedsToBeMeasuredButWhomsNameCannotBeSpoken = 0;

if (StrTheStringThatNeedsToBeMeasuredButWhomsNameCannotBeSpoken)
while (*StrTheStringThatNeedsToBeMeasuredButWhomsNameCannotBeSpoken++)
SizTheLengthOfTheStringThatNeedsToBeMeasuredButWhomsNameCannotBeSpoken++;

return SizTheLengthOfTheStringThatNeedsToBeMeasuredButWhomsNameCannotBeSpoken;

}

HTH,
AvK
 
R

Richard Tobin

So this is your home-rolled strlen?
[/QUOTE]
Yes Fred, it is. Note it is null pointer safe.

For some value of "safe". I'd rather get a segmentation fault,
so that I detect my mistake sooner.

Of course, you could consistently treat a null pointer as equivalent
to an empty string, but you'd need a complete suite of similarly
modified string functions. You'd want Strcmp("", 0) to be 0, and
Printf("%s", (char *)0) to print nothing, and so on.

-- Richard
 
R

Richard Tobin

For some value of "safe". I'd rather get a segmentation fault,
so that I detect my mistake sooner.

By the way, I didn't mean to imply that Joe was seriously suggesting
that anyone use his function. I just wanted to make the point about
"null pointer safe".

-- Richard
 
I

Ike Naar

"You talk like a fag, and you're shit's all fucked up." - Idiocracy,
Mike Judge, 2005

Paraphrasing again?
"You talk like a fag, and your shit's all retarded" - Idiocracy,
Mike Judge, 2006
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,565
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top