Warning to newbies

S

santosh

spinoza1111 said:
spinoza1111wrote:



Yes.

I noticed that it fails for many cases of bad input.

Doesn't look bad to me below, will try out the new cases on my lastest
vrsion [ ... ] Try the new version and I will try all your tests.

I tried your latest version (not the one below, but the one in your
other response to me:

<http://groups.google.com/group/comp.lang.c/msg/5c2c92e239aeaa77?
hl=en>

I did a basic test, and one curious observation:

replace(" a stupid errorstupid errorHeystupid errors", "stupid
error", "+") gives:

[space]a[space]++Hey+

shouldn't it give:

[space]a[space]++Hey+s

since

replace(" a stupid errorstupid errorHeystupid errord", "stupid
error", "+") gives:

[space]a[space]++Hey+d

as expected. So why not in the same in the first call above?

Here is what I quickly came up with. It does waste some space in
guessing the size of an array, to avoid repeated realloc() calls or
calling strstr() 2n times. Some basic testing seems to show it works
as expected.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char **find_all(
char *str,
char *seq,
size_t lstr,
size_t lseq,
unsigned *ntimes) {
char **p_seqs;

if (!str || !seq || !ntimes) return NULL;
else if (!(p_seqs = calloc(lstr/lseq, sizeof *p_seqs))) return NULL;

for (unsigned i = *ntimes = 0; i < (lstr/lseq); i++) {
p_seqs = strstr(str, seq);
if (p_seqs) {
str += lseq;
*ntimes += 1;
} else break;
}
return p_seqs;
}

char *replace_all(
char *s,
char *r,
size_t ls,
size_t lr,
char **p_seqs,
unsigned n,
size_t lseq) {
char *str;
size_t lstr;

if (!s || !r || !p_seqs) return NULL;

lstr = (ls - (n * lseq)) + (n * lr) + 1;
if (str = malloc(lstr * sizeof *str)) {
size_t i = 0;
while (*s) {
if (s == *p_seqs) {
strcpy(str+i, r);
i += lr;
s += lseq;
p_seqs++;
} else {
str[i++] = *s;
s++;
}
}
str = '\0';
}
return str;
}

int main(int argc, char **argv) {
unsigned n;
char **p_seqs;
char *final_str;
char *usage = "Usage: program string substring replacement\n";
size_t lstr, lseq, lrep;

if(argc != 4) {
fputs(usage, stderr);
return EXIT_FAILURE;
}
lstr = strlen(argv[1]);
lseq = strlen(argv[2]);
lrep = strlen(argv[3]);
if (!lstr || !lseq || !lrep || lstr < lseq) {
fputs(usage, stderr);
return EXIT_FAILURE;
}

p_seqs = find_all(argv[1], argv[2], lstr, lseq, &n);
if (!p_seqs) {
fputs("find_all() error.\n", stderr);
return EXIT_FAILURE;
}
final_str = replace_all(argv[1], argv[3], lstr, lrep, p_seqs, n,
lseq);
if (final_str) {
printf("Result:\n%s\n", final_str);
free(p_seqs);
free(final_str);
} else {
fputs("replace_all() error.\n", stderr);
return EXIT_FAILURE;
}
return 0;
}
 
S

spinoza1111

Richard said:
Today has officially been declared "Typo Sunday". Of course you meant
<stdlib.h>

You are an incompetent, and I believe SAMS pays you to post, because
they are an unethical publisher who caused a competent editor friend
of mine to be jailed when she sued them pro se for money they owed
her.

Because you're an incompetent, useful ONLY for the most detailed and
trivial factoids, indeed the sort of changes which competent people
make all the time when porting C code, and because you're insecure,
you throw your weight around here, fat boy.

Competent people NEVER blindly "port" C, fat boy. This is because
competent people know that C is too close to the machine for us to
have anything like assurance that we can blindly port code. Therefore,
it is probably a good idea NOT to make the zany little changes you
recommend, because they lull fools like you into porting code that
then breaks, perhaps even crashing A320s or Toyotas for all we know.

Although I initially accepted your foolish ideas about quoting rather
than angle-bracketing included files, I am beginning to change my
mind. Perhaps C code written for a specific compiler should have a
look and feel unique to that compiler, with let us say upper case type
suffixes on file names. This would inform the reader that we're using
Windows, and it would have the added benefit of driving you bat shit.
 
S

santosh

Willem said:
santosh wrote:
) Anyway, I didn't follow the previous discussions in the thread
) closely, but for what it appears to do, your code appears to be an
) overkill. What about a solution involving strstr(), malloc()/realloc()
) and strcat()?

I've never liked strcat(), and I'm not sure about the performance of
realloc(), so this is roughly what I would do:

#include <string.h>

char *replace(char *string, char *replace, char *with)
{
size_t replace_len = strlen(replace);
size_t with_len = strlen(with);
size_t result_len;
char *string_ptr, *search_ptr, *result_ptr;
char *result;

/* Determine result length */
result_len = 0;
string_ptr = string;
while (search_ptr = strstr(string_ptr, replace)) {
result_len += (search_ptr - string_ptr);
result_len += with_len;
string_ptr = search_ptr + replace_len;
}
result_len += strlen(string_ptr) + 1;

if (result = malloc(result_len)) {
/* Do the replacement */
string_ptr = string;
result_ptr = result;
while (search_ptr = strstr(string_ptr, replace)) {
memcpy(result_ptr, string_ptr, search_ptr - string_ptr);
result_ptr += (search_ptr - string_ptr);
memcpy(result_ptr, with, with_len);
result_ptr += with_len;
string_ptr = search_ptr + replace_len;
}
*result_ptr = 0;
}
return result;
}


Of course, this does the loop twice. I have no idea if this would
outperform the realloc() method, basically you either have to do 1
additional strstr() per match, or one additional realloc() per match.

I'll get post another reply after I've tested your function above. I
posted my version in response to one of spinoza1111's posts. It
neither does an additional strstr() per match, nor uses realloc() at
all, but it does allocate an array based on guessing, so for a
contrived set of inputs, you could make it waste a large amount of
space. The alternative would've been to use strstr() 2n times, as Ben
did. Anyway both yours' and Ben's functions are much more compact than
mine.

<snip>
 
J

James

[...]
Do you think it could be beneficial to be able to do something like:




char const* src_string = "ABAB";


/* get's size minus null terminator. */
size_t new_size = replace_get_size(string, "A", "XXXX");
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^


OOPS! That should be:


size_t new_size = replace_get_size(src_string, "A", "XXXX");



[...]
 
W

Willem

Ben Bacarisse wrote:
) Snap! Here is what I'd do. I think it is structurally the same:

It is, yes. Minus one bug/mistake that I think I made.

) char *replace(const char *src, const char *match, const char *replacement)
) {
) size_t mlen = strlen(match), matches = 0;
) for (const char *t, *s = src; t = strstr(s, match); s = t + mlen)
) ++matches;
) size_t rlen = strlen(replacement);
) char *result = malloc(strlen(src) + matches*rlen - matches*mlen + 1);
) if (result) {
) char *dst = result;
) const char *s = src;
) for (const char *t; t = strstr(s, match); s = t + mlen) {
) memcpy(dst, s, t - s);
) memcpy(dst += t - s, replacement, rlen);
) dst += rlen;
) }
) strcpy(dst, s);

Here's the bit that I think I forgot.

) }
) return result;
) }

<snip>


SaSW, Willem
--
Disclaimer: I am in no way responsible for any of the statements
made in the above text. For all I know I might be
drugged or something..
No I'm not paranoid. You all think I'm paranoid, don't you !
#EOT
 
S

santosh

spinoza1111 said:
Hopefully a final version, with free storage calls for both the
replaced strings and the linked list created inside replace(). I found
a major memory leak in the previous version owing to the use of an
incorrect index in a test, and this has been fixed. The leak didn't
occur in debug mode until I added code to free strings returned by
replace(), and I'd propose some sort of macro interface to malloc()
and free() is needed in test. It's nuts in Microsoft C++/C that debug
mode would conceal leakages.

The code is followed by the expected output.

<snip code>

I attempted to compile this. There were three compile errors. One to
do with the TESTER macro, one that was generated because of string
crossing line boundaries, and finally one because you called strlen()
without including string.h, but you meant to call your own strLen()
I'm sure. So I fixed these and compiled and ran it. It does produce
the expected output for the test cases you include in main(), but I
commented out both the TESTER macro and your main() definition and
supplied my own given below. This allows me to test your function from
the command-line without having to include each test case in the code
and go through the build process each time.

int main(int argc, char **argv) {
char *result;

printf("Output:\n%s\n",
replace(argv[1], argv[2], argv[3]));
free(result);
return 0;
}

Again I'm seeing some anomalous output.

For:

$ ./spinoza1111_3 "foo bar" "foo bar" "bas"

we have the expected output

Output:
bas

Also for:

$ ./spinoza1111_3 "foo barfoo bar" "foo bar" "bas"

Output:
basbas

But:

$ ./spinoza1111_3 "foo barfoo barf" "foo bar" "bas"

we get:

Output:
basbas

and not

Output:
basbasf

as one would expect.

But:

$ ./spinoza1111_3 "foo barfoo barq" "foo bar" "bas"

gives:

Output:
basbasq

as expected. This problem was there in your earlier versions too. More
generally, if the last character of the "master" string happens to be
the same as the first character of the target string, it is silently
dropped. I haven't examined your code in sufficient detail to suggest
the fix though. I'm just testing it out. Also there may be more such
cases of unexpected output.
 
W

Willem

santosh wrote:
) Willem wrote:
)> santosh wrote:
)> ) Anyway, I didn't follow the previous discussions in the thread
)> ) closely, but for what it appears to do, your code appears to be an
)> ) overkill. What about a solution involving strstr(), malloc()/realloc()
)> ) and strcat()?
)>
)> I've never liked strcat(), and I'm not sure about the performance of
)> realloc(), so this is roughly what I would do:
)>
)> #include <string.h>
)>
)> char *replace(char *string, char *replace, char *with)
)> {
)> size_t replace_len = strlen(replace);
)> size_t with_len = strlen(with);
)> size_t result_len;
)> char *string_ptr, *search_ptr, *result_ptr;
)> char *result;
)>
)> /* Determine result length */
)> result_len = 0;
)> string_ptr = string;
)> while (search_ptr = strstr(string_ptr, replace)) {
)> result_len += (search_ptr - string_ptr);
)> result_len += with_len;
)> string_ptr = search_ptr + replace_len;
)> }
)> result_len += strlen(string_ptr) + 1;
)>
)> if (result = malloc(result_len)) {
)> /* Do the replacement */
)> string_ptr = string;
)> result_ptr = result;
)> while (search_ptr = strstr(string_ptr, replace)) {
)> memcpy(result_ptr, string_ptr, search_ptr - string_ptr);
)> result_ptr += (search_ptr - string_ptr);
)> memcpy(result_ptr, with, with_len);
)> result_ptr += with_len;
)> string_ptr = search_ptr + replace_len;
)> }

/* Bug here: change the following line */

)> *result_ptr = 0;

/* The previous line should be: */

strcpy(result_ptr, string_ptr);

/* because otherwise the last bit is dropped off */

)> }
)> return result;
)> }
)>
)>
)> Of course, this does the loop twice. I have no idea if this would
)> outperform the realloc() method, basically you either have to do 1
)> additional strstr() per match, or one additional realloc() per match.
)
) I'll get post another reply after I've tested your function above. I
) posted my version in response to one of spinoza1111's posts. It
) neither does an additional strstr() per match, nor uses realloc() at
) all, but it does allocate an array based on guessing, so for a
) contrived set of inputs, you could make it waste a large amount of
) space. The alternative would've been to use strstr() 2n times, as Ben
) did. Anyway both yours' and Ben's functions are much more compact than
) mine.

There is at least one flaw in mine; I forgot to copy the final bit of
string.


SaSW, Willem
--
Disclaimer: I am in no way responsible for any of the statements
made in the above text. For all I know I might be
drugged or something..
No I'm not paranoid. You all think I'm paranoid, don't you !
#EOT
 
S

spinoza1111

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!
 
S

spinoza1111

spinoza1111wrote:
Doesn't look bad to me below, will try out the new cases on my lastest
vrsion [ ... ] Try the new version and I will try all your tests.

I tried your latest version (not the one below, but the one in your
other response to me:

<http://groups.google.com/group/comp.lang.c/msg/5c2c92e239aeaa77?
hl=en>

I did a basic test, and one curious observation:

    replace(" a stupid errorstupid errorHeystupid errors", "stupid
error", "+") gives:

    [space]a[space]++Hey+

shouldn't it give:

    [space]a[space]++Hey+s

since

    replace(" a stupid errorstupid errorHeystupid errord", "stupid
error", "+") gives:

    [space]a[space]++Hey+d

as expected. So why not in the same in the first call above?

Here is what I quickly came up with. It does waste some space in
guessing the size of an array, to avoid repeated realloc() calls or
calling strstr() 2n times. Some basic testing seems to show it works
as expected.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char **find_all(
                char *str,
                char *seq,
                size_t lstr,
                size_t lseq,
                unsigned *ntimes) {
        char **p_seqs;

        if (!str || !seq || !ntimes) return NULL;
        else if (!(p_seqs = calloc(lstr/lseq, sizeof *p_seqs))) return NULL;

        for (unsigned i = *ntimes = 0; i < (lstr/lseq); i++) {
                p_seqs = strstr(str, seq);
                if (p_seqs) {
                        str += lseq;
                        *ntimes += 1;
                } else break;
        }
        return p_seqs;

}

char *replace_all(
                char *s,
                char *r,
                size_t ls,
                size_t lr,
                char **p_seqs,
                unsigned n,
                size_t lseq) {
        char *str;
        size_t lstr;

        if (!s || !r || !p_seqs) return NULL;

        lstr = (ls - (n * lseq)) + (n * lr) + 1;
        if (str = malloc(lstr * sizeof *str)) {
                size_t i = 0;
                while (*s) {
                        if (s == *p_seqs) {
                                strcpy(str+i, r);
                                i += lr;
                                s += lseq;
                                p_seqs++;
                        } else {
                                str[i++] = *s;
                                s++;
                        }
                }
                str = '\0';
        }
        return str;

}

int main(int argc, char **argv) {
        unsigned n;
        char **p_seqs;
        char *final_str;
        char *usage = "Usage: program string substring replacement\n";
        size_t lstr, lseq, lrep;

        if(argc != 4) {
                fputs(usage, stderr);
                return EXIT_FAILURE;
        }
        lstr = strlen(argv[1]);
        lseq = strlen(argv[2]);
        lrep = strlen(argv[3]);
        if (!lstr || !lseq || !lrep || lstr < lseq) {
                fputs(usage, stderr);
                return EXIT_FAILURE;
        }

        p_seqs = find_all(argv[1], argv[2], lstr, lseq, &n);
        if (!p_seqs) {
                fputs("find_all() error.\n", stderr);
                return EXIT_FAILURE;
        }
        final_str = replace_all(argv[1], argv[3], lstr, lrep, p_seqs, n,
lseq);
        if (final_str) {
                printf("Result:\n%s\n", final_str);
                free(p_seqs);
                free(final_str);
        } else {
                fputs("replace_all() error.\n", stderr);
                return EXIT_FAILURE;
        }
        return 0;



}


Yes. As I told Ike, there was "one more" bug: the exit from the
while(-1) needed to update the main index and did not. Use the last
posted version to test.

Basically, Willem and Bacarisse are demonstrating concurrently that
the best way, in terms of time management and getting a working
solution, is to use string.h. But I decided not to. Even though my
solution took only a short amount of time, it has had some gotchas and
may have more. It needs to be "proven correct" by way of an analysis
expressible in English, perhaps associated with a stress test. But I
shall have to do this on Chinese New Year, since I have a busy week.

I also checked the standard string library, and it does not have a
replace function, so their effort and mine makes sense.

Of course, Dijkstra would have derived the code from the proof which
is what you have to do when you propose to reinvent the broken wheel
of C string handling. To live outside the law you must be honest.

Thanks for the bug reports. Here is the version of the code with your
latest and greatest test and its expected console output.



// ***************************************************************
// * *
// * 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 *
// * *
// * ----------------------------------------------------------- *
// * *
// * "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")
TESTER(ptrResult,
" a stupid errorstupid errorHeystupid errors",
"stupid error",
"+",
" a ++Hey+s")
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"

Expect " a ++Hey+s":
" a ++Hey+s"



Testing complete: check output carefully!
 
S

santosh

spinoza1111 said:
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.

<snip>

This version seems to work for all the cases I could think of. Will
see your code in more detail as time allows. I'm not clear why you've
worked so hard to bypass string.h functionality, even to the extent of
rolling your own strLen(). Is your objection towards the fact that
string.h imposes the paradigm of nul terminated strings, which you
don't like?
 
S

spinoza1111

spinoza1111wrote:


<snip code>

I attempted to compile this. There were three compile errors. One to
do with the TESTER macro, one that was generated because of string
crossing line boundaries, and finally one because you called strlen()
without including string.h, but you meant to call your own strLen()

Don't know how that crept in but it is not in the latest version
posted, I'm sure. Let me know if it is.
I'm sure. So I fixed these and compiled and ran it. It does produce

In other words, you're a professional. There are three types of people
here:

1. Heathfield and Seebach, who see something trivial and start
yapping about thousands of bugs and trash talking others.

2. Willem and Bacarisse, who don't want to talk to me since I give
them a ration of shit, and who've worked on their own solution, which
is probably the best practical solution, since it uses the existing
string library. My goal was NOT to use it.

3. You and Ike Naar, who might think I'm a bozo and twerp but work
professionally to solve a problem.

the expected output for the test cases you include in main(), but I
commented out both the TESTER macro and your main() definition and
supplied my own given below. This allows me to test your function from
the command-line without having to include each test case in the code
and go through the build process each time.

int main(int argc, char **argv) {
        char *result;

        printf("Output:\n%s\n",
                replace(argv[1], argv[2], argv[3]));
        free(result);
        return 0;

}

Again I'm seeing some anomalous output.

For:

$ ./spinoza1111_3 "foo bar" "foo bar" "bas"

we have the expected output

Output:
bas

Also for:

$ ./spinoza1111_3 "foo barfoo bar" "foo bar" "bas"

Output:
basbas

But:

$ ./spinoza1111_3 "foo barfoo barf" "foo bar" "bas"

we get:

Output:
basbas

and not

Output:
basbasf

Fixed the problem. Try the last version posted.
as one would expect.

But:

$ ./spinoza1111_3 "foo barfoo barq" "foo bar" "bas"

gives:

Output:
basbasq

as expected. This problem was there in your earlier versions too. More
generally, if the last character of the "master" string happens to be
the same as the first character of the target string, it is silently
dropped. I haven't examined your code in sufficient detail to suggest
the fix though. I'm just testing it out. Also there may be more such
cases of unexpected output.

Thanks for this hard work. I have fixed the problem, see the end of
this thread.

I am trying to think through why I so hate the string library when
Willem and Bacarisse may have spent less time on coming up with a
version with fewer gotchas (although they may have bugs in their code,
too).

My planned essay on this code, an informal correctness proof, has
gotta wait to Chinese New Year. I think it will start with a regular
expression where one symbol is used for all target strings and involve
adding asserts to the effect that "an unreplaced string" or "a target"
has been found in this regular expression:

([unreplacedString][target])*

This may involve relabeling the indexes to something more meaningful.
 
S

spinoza1111

spinoza1111wrote:
<snip>

This version seems to work for all the cases I could think of. Will
see your code in more detail as time allows. I'm not clear why you've
worked so hard to bypass string.h functionality, even to the extent of
rolling your own strLen(). Is your objection towards the fact that
string.h imposes the paradigm of nul terminated strings, which you
don't like?

Yes. I think it rots the brain (grin).

I started out when we had (on an 8K 1401) not to reinvent the wheel,
but to invent it, and as I relate in my book, "Build Your Own .Net
Language and Compiler" an older spiritual mentor from IBM wrote his
own compilers to support business programming on the 7040 in the 1950s
because within the old IBM "it was easier to ask forgiveness than
permission".

But, Job One today is using existing tools effectively, and I'm glad
I've left the field (after thirty years) since I have little respect
for existing tools. I think they encapsulate mistakes, and I think
they were selected because of social prestige: University of Chicago
nerds did better software than C at the time C was invented, but
Princeton and Bell Labs had more cachet.

But whenever I get down and dirty I discover that I need to make a
deep analysis of what it is I am doing. I don't think I've mastered
what's going on in "my" replace. I've fixed bugs and the whole project
has only taken a couple of hours, but there may still be gotchas,
whether logical or in C semantics (memory leaks).
 
S

spinoza1111

santosh wrote:
) Willem wrote:
)> santosh wrote:

)> ) Anyway, I didn't follow the previous discussions in the thread
)> ) closely, but for what it appears to do, your code appears to be an
)> ) overkill. What about a solution involving strstr(), malloc()/realloc()
)> ) and strcat()?
)>
)> I've never liked strcat(), and I'm not sure about the performance of
)> realloc(), so this is roughly what I would do:
)>
)>  #include <string.h>
)>
)>  char *replace(char *string, char *replace, char *with)
)>  {
)>    size_t replace_len = strlen(replace);
)>    size_t with_len = strlen(with);
)>    size_t result_len;
)>    char *string_ptr, *search_ptr, *result_ptr;
)>    char *result;
)>
)>    /* Determine result length */
)>    result_len = 0;
)>    string_ptr = string;
)>    while (search_ptr = strstr(string_ptr, replace)) {
)>      result_len += (search_ptr - string_ptr);
)>      result_len += with_len;
)>      string_ptr = search_ptr + replace_len;
)>    }
)>    result_len += strlen(string_ptr) + 1;
)>
)>    if (result = malloc(result_len)) {
)>      /* Do the replacement */
)>      string_ptr = string;
)>      result_ptr = result;
)>      while (search_ptr = strstr(string_ptr, replace)) {
)>        memcpy(result_ptr, string_ptr, search_ptr - string_ptr);
)>        result_ptr += (search_ptr - string_ptr);
)>        memcpy(result_ptr, with, with_len);
)>        result_ptr += with_len;
)>        string_ptr = search_ptr + replace_len;
)>      }

/* Bug here: change the following line */

)>      *result_ptr = 0;

/* The previous line should be: */

        strcpy(result_ptr, string_ptr);

/* because otherwise the last bit is dropped off */

)>    }
)>    return result;
)>  }
)>
)>
)> Of course, this does the loop twice.  I have no idea if this would
)> outperform the realloc() method, basically you either have to do 1
)> additional strstr() per match, or one additional realloc() per match.
)
) I'll get post another reply after I've tested your function above. I
) posted my version in response to one ofspinoza1111'sposts. It
) neither does an additional strstr() per match, nor uses realloc() at
) all, but it does allocate an array based on guessing, so for a
) contrived set of inputs, you could make it waste a large amount of
) space. The alternative would've been to use strstr() 2n times, as Ben
) did. Anyway both yours' and Ben's functions are much more compact than
) mine.

There is at least one flaw in mine; I forgot to copy the final bit of
string.

So did I. I haven't had time to look at your code being busy with mine
but it looks like an effective use of the library.

The point being that a professional, whether or not he uses string.H,
is someone who fixes bugs and does not say "this is just a fast and
dirty solution". Nor is he one who gets a hair up his ass about
quoting malloc.h.
 
S

santosh

spinoza1111 wrote:
Thanks for the bug reports. Here is the version of the code with your
latest and greatest test and its expected console output.



// ***************************************************************
// * *
// * 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 *
// * *
// * ----------------------------------------------------------- *
// * *
// * "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

Is this necessary for MS Visual C++?

It isn't needed for gcc, since stdlib.h already has the declarations
for malloc/free.
#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);

I don't know if this is the very latest version of your code, but as I
said, you're still calling standard library strlen() above, without
including string.h. This means that strReplacement with be converted
to an int value and so will the value returned by the strlen()
function, since it has no declaration in scope.

I guess you meant to call your strLen() instead. Didn't get any other
compiler errors. And now it seems to work fine for all inputs I could
think of.

<snip rest>
 
S

spinoza1111

Your hope is in vain.
replace("abab","ba","ba") = "aba" ?

No, I fixed that. Here is a version just for you, with this test
added.



// ***************************************************************
// * *
// * 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 *
// * *
// * ----------------------------------------------------------- *
// * *
// * "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")
TESTER(ptrResult,
" a stupid errorstupid errorHeystupid errors",
"stupid error",
"+",
" a ++Hey+s")
TESTER(ptrResult,
"foo barfoo barf",
"foo bar",
"bas",
"basbasf")
TESTER(ptrResult,
"abab",
"ba",
"ba",
"abab")
printf("\n\nTesting complete: check output carefully!\n\n");
return 0;
}

Here is its console output:


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"

Expect " a ++Hey+s":
" a ++Hey+s"

Expect "basbasf":
"basbasf"

Expect "abab":
"abab"



Testing complete: check output carefully!
 
S

spinoza1111

spinoza1111wrote:

<snip>








Is this necessary for MS Visual C++?

No it is not. I've taken it out.
It isn't needed for gcc, since stdlib.h already has the declarations
for malloc/free.









I don't know if this is the very latest version of your code, but as I
said, you're still calling standard library strlen() above, without
including string.h. This means that strReplacement with be converted
to an int value and so will the value returned by the strlen()
function, since it has no declaration in scope.

I guess you meant to call your strLen() instead. Didn't get any other
compiler errors. And now it seems to work fine for all inputs I could
think of.

I have fixed strlen to be my own strLength and everything still works,
but won't repost until I have more significant changes, to spare
bandwidth hogging.

Thanks again.
 
S

Seebs

Just asking out of interest, would a post-increment enable any
significant optimisations by the compiler that wouldn't be possible
with a pre-increment?

In this context, no, because they're semantically equivalent (no use is made
of the value on either end, and there's sequence points between this and
anything else), so the compiler can treat them as interchangeable.

-s
 
S

Seebs

Anyway, I didn't follow the previous discussions in the thread
closely, but for what it appears to do, your code appears to be an
overkill. What about a solution involving strstr(), malloc()/realloc()
and strcat()?

My code for this was written in about five minutes, I have not yet found a bug
in it (although it does have the documented limitation that, as of this
writing, it simply assumes that "%" will be the first character of "%s";
since it only has to run on two strings, and they're in the same module,
I was okay with that), and ran correctly on the first try. (It would have
been the second try, except that I'd just done something sort of similar
half an hour earlier and made a fencepost error there, which kept the question
clearly in mind.)

I did analyze the problem carefully, and I concluded that it was simple enough
and easy enough to get right in this particular case that it would be better
to write a fairly simple loop which the reader could verify by inspection
than to try to solve the general problem.

-s
 

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

No members online now.

Forum statistics

Threads
474,262
Messages
2,571,056
Members
48,769
Latest member
Clifft

Latest Threads

Top