In the old version, replace("banana","ana","oat") gives "boat".
In the new version it gives "boatn".
Both outputs are not what one would expect.
Great test, thank you. The problem was at the bottom of the loop to
find matches (the while (-1) loop). The main string pointer needed to
be updated.
A new version and its output are at the bottom of this post.
I can see where Ben's and Willem's version, which use string.h, are
easier and less complex. However, I'd ask of them, doesn't string.h
have a replace? My goal is to exit "the Truman show that is C by way
of C", as I've said, and this means not using the string library at
all.
Ben's and Willem's version is an example of "competent C programming"
where part of competence in a bureaucracy is staying within the little
box you've been assigned. Well, thank God I'm not a programmer
anymore, since staying within the box is deskilling and an expense of
spirit in a waste of shame.
I need next to come up with an informal proof in English that this
code really works, such as could be aired at a structured walkthrough
from which thugs have been excluded. But keep these great bug reports
coming.
// ***************************************************************
// * *
// * 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 *
// * *
// * ----------------------------------------------------------- *
// * *
// * "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 "malloc.h" // Per RH ess muss sein
#include <stdlib.h>
// ***** Segmentation *****
struct TYPsegmentstruct
{ char * strSegment;
long lngSegmentLength;
int intReplaceAtEnd;
struct TYPsegmentstruct * ptrNext; };
// ---------------------------------------------------------------
// Calculate string length
//
//
long strLen(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)
{
char * ptrIndex0;
char * ptrIndex1;
char * ptrIndex2;
char * ptrIndex3;
char * strNew;
char * strNewStart;
long lngNewLength;
long lngCount;
long lngReplacementLength;
struct TYPsegmentstruct * ptrSegmentStructStarts;
struct TYPsegmentstruct * ptrSegmentStruct;
struct TYPsegmentstruct * ptrSegmentStructPrev;
lngReplacementLength = strlen(strReplacement);
if (!*strTarget)
{
printf("Error in calling replace(): target can't be null");
abort();
}
ptrIndex1 = strMaster;
ptrSegmentStructPrev = 0;
lngNewLength = 0;
while(*ptrIndex1)
{
ptrIndex0 = ptrIndex1;
while (-1)
{
for(;
*ptrIndex1 && *ptrIndex1 != *strTarget;
ptrIndex1++);
for(ptrIndex2 = strTarget, ptrIndex3 = ptrIndex1;
*ptrIndex3
&&
*ptrIndex2
&&
*ptrIndex3 == *ptrIndex2;
ptrIndex3++, ptrIndex2++);
if (!*ptrIndex2) break;
ptrIndex1 = ptrIndex3;
if (!*ptrIndex3) break;
}
if (!(ptrSegmentStruct =
malloc(sizeof(struct TYPsegmentstruct))))
abort();
ptrSegmentStruct->strSegment = ptrIndex0;
ptrSegmentStruct->intReplaceAtEnd = *ptrIndex2 ? 0 : -1;
ptrSegmentStruct->lngSegmentLength =
ptrIndex1 - ptrIndex0;
lngNewLength += ptrSegmentStruct->lngSegmentLength +
(!*ptrIndex2
?
lngReplacementLength
:
0);
ptrSegmentStruct->ptrNext = 0;
if (ptrSegmentStructPrev != 0)
ptrSegmentStructPrev->ptrNext = ptrSegmentStruct;
else
ptrSegmentStructStarts = ptrSegmentStruct;
ptrSegmentStructPrev = ptrSegmentStruct;
ptrIndex1 = ptrIndex3;
}
if (!(strNewStart = malloc(lngNewLength + 1))) abort();
strNew = strNewStart;
ptrSegmentStruct = ptrSegmentStructStarts;
while (ptrSegmentStruct)
{
for (ptrIndex1 = ptrSegmentStruct->strSegment, lngCount = 0;
lngCount < ptrSegmentStruct->lngSegmentLength;
ptrIndex1++, lngCount++, strNew++)
*strNew = *ptrIndex1;
if (ptrSegmentStruct->intReplaceAtEnd)
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) \
{ \
printf("Expect \"%s\":\n\"%s\"\n\n", \
(expected), \
resultPtr = replace((master), \
(target), \
(replacement))); \
free(resultPtr); \
}
// ---------------------------------------------------------------
// Main procedure
//
//
int main()
{
char *ptrResult;
printf("\nReplace\n\n\n");
TESTER(ptrResult,
"a stupid error",
"stupid error",
"miracle",
"a miracle")
TESTER(ptrResult,
"a stupid error",
"stupid",
"miracle",
"a miracle error")
TESTER(ptrResult,
"the stupid error",
"the stupid error",
"a miracle",
"a miracle")
TESTER(ptrResult,
"the miracle",
"the",
"a",
"a miracle")
TESTER(ptrResult,
"a miraclsnirpKamunkle",
"snirpKamunkle",
"e",
"a miracle")
TESTER(ptrResult,
"a miraclesnirpKamunkle",
"a miracle",
"",
"snirpKamunkle")
TESTER(ptrResult,
" a miraclesnirpKamunkle",
"a miracle",
"",
" snirpKamunkle")
TESTER(ptrResult,
" a miraclesnirpKamunklea miraclea miracle",
"a miracle",
"",
" snirpKamunkle")
TESTER(ptrResult,
"a miracle a miraclesnirpKamunkle a Miraclea miraclea
miracle",
"a miracle",
"",
" snirpKamunkle a Miracle")
TESTER(ptrResult,
"a stupid errord",
"stupid error",
"miracle",
"a miracled")
TESTER(ptrResult,
"a stupid errod",
"stupid error",
"miracle",
"a stupid errod")
TESTER(ptrResult,
"a sstupid error",
"stupid error",
"miracle",
"a smiracle")
TESTER(ptrResult,
"a stupid errorstupid error",
"stupid error",
"miracle",
"a miraclemiracle")
TESTER(ptrResult,
"a stupid error stupiderror",
"stupid error",
"miracle",
"a miracle stupiderror")
TESTER(ptrResult,
"bbbbbbbbbb",
"b",
"a",
"aaaaaaaaaa")
TESTER(ptrResult,
"In the halls of R'yleh great %s lies dreaming",
"%s",
"Cthulu",
"In the halls of R'yleh great Cthulu lies dreaming")
TESTER(ptrResult,
"%s%s%s%s%s%s",
"%s",
"Cthulu",
"CthuluCthuluCthuluCthuluCthuluCthulu")
TESTER(ptrResult,
"banana",
"ana",
"oat",
"boatna")
printf("\n\nTesting complete: check output carefully!\n\n");
return 0;
}
Replace
Expect "a miracle":
"a miracle"
Expect "a miracle error":
"a miracle error"
Expect "a miracle":
"a miracle"
Expect "a miracle":
"a miracle"
Expect "a miracle":
"a miracle"
Expect "snirpKamunkle":
"snirpKamunkle"
Expect " snirpKamunkle":
" snirpKamunkle"
Expect " snirpKamunkle":
" snirpKamunkle"
Expect " snirpKamunkle a Miracle":
" snirpKamunkle a Miracle"
Expect "a miracled":
"a miracled"
Expect "a stupid errod":
"a stupid errod"
Expect "a smiracle":
"a smiracle"
Expect "a miraclemiracle":
"a miraclemiracle"
Expect "a miracle stupiderror":
"a miracle stupiderror"
Expect "aaaaaaaaaa":
"aaaaaaaaaa"
Expect "In the halls of R'yleh great Cthulu lies dreaming":
"In the halls of R'yleh great Cthulu lies dreaming"
Expect "CthuluCthuluCthuluCthuluCthuluCthulu":
"CthuluCthuluCthuluCthuluCthuluCthulu"
Expect "boatna":
"boatna"
Testing complete: check output carefully!