By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
434,640 Members | 2,118 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 434,640 IT Pros & Developers. It's quick & easy.

Replacing a word in a string

P: n/a
Hi guys!

I like C because is fun. So, I wrote this function for the lcc-win32
standard library: strrepl.

I thought that with so many "C heads" around, maybe we could improve it
in a collective brainstorming session.

Let's discuss some C here, for a change :-)

Specs:
-----
Function: strrepl

Synopsis

#include <string.h>
char *strrepl(char *InputString, char *StringToFind,
char *Replacement, char *Output);
Description

The strrepl function replaces in InputString all occurrences of
StringToFind by Replacement, writing the modified contents into the
Output string. The original input string is not modified.

If the Output argument is NULL, strrepl will return the space that would
be needed (including the terminating zero) for the replacement.

If Replacement is NULL and Output is not NULL, all occurrences of
StringToFind will be erased.

Returns

The strrepl function returns the needed length for the replacements if
its Output argument is NULL. If not, it returns the number of
replacements done.

Code:
-----
#include <string.h>
int strrepl(char *InputString,char *StringToFind,
char *StringToReplace,char *output)
{
char *offset = NULL, *CurrentPointer = NULL;
int insertlen;
int findlen = strlen(StringToFind);
int result = 0;

if (StringToReplace)
insertlen = strlen(StringToReplace);
else
insertlen = 0;
if (output) {
if (output != InputString)
memmove(output,InputString,strlen(InputString)+1);
InputString = output;
}
else
result = strlen(InputString)+1;

while (*InputString) {
offset = strstr(!offset?InputString:CurrentPointer,StringTo Find);
if (offset == NULL)
break;
CurrentPointer = (offset + (output ? insertlen : findlen));
if (output) {
strcpy (offset, (offset + findlen));
memmove (offset + insertlen,
offset, strlen (offset) + 1);
if (insertlen)
memcpy (offset, StringToReplace, insertlen);
result++;
}
else {
result -= findlen;
result += insertlen;
}
}
return result;
}

All kinds of comments are welcome, regarding the code, the interface
design, the documentation, etc etc.

jacob
Dec 6 '05 #1
Share this Question
Share on Google+
35 Replies


P: n/a


jacob navia wrote On 12/06/05 15:41,:

Synopsis

#include <string.h>
char *strrepl(char *InputString, char *StringToFind,
char *Replacement, char *Output);
[...]

Code:
-----
#include <string.h>
int strrepl(char *InputString,char *StringToFind,
char *StringToReplace,char *output)


A diagnostic is required if both the declaration
and the definition appear in the same translation unit.
(In C, anyhow. That other language you're fond of may
have different rules.)

--
Er*********@sun.com

Dec 6 '05 #2

P: n/a
jacob navia wrote:
Hi guys!

I like C because is fun. So, I wrote this function for the lcc-win32
standard library: strrepl.

I thought that with so many "C heads" around, maybe we could improve it
in a collective brainstorming session.

Let's discuss some C here, for a change :-)

Specs:
-----
Function: strrepl

Synopsis

#include <string.h>
char *strrepl(char *InputString, char *StringToFind, ^^^^^^
ITYM: int or size_t char *Replacement, char *Output);
In order to avoid name clashes, I'd rather call the function
str_repl or strRepl or replaceSubstring.
Description

The strrepl function replaces in InputString all occurrences of
StringToFind by Replacement, writing the modified contents into the
Output string. The original input string is not modified.
Then your prototype is wrong: You want
size_t str_repl(const char* restrict InputString,
const char* StringToFind,
const char* Replacement,
char* restrict Output);
to avoid this. Or do away with the restrict if you want
to express that the original string is not modified via
InputString.
If the Output argument is NULL, strrepl will return the space that would
be needed (including the terminating zero) for the replacement.

If Replacement is NULL and Output is not NULL, all occurrences of
StringToFind will be erased.

Returns

The strrepl function returns the needed length for the replacements if
its Output argument is NULL. If not, it returns the number of
replacements done.
I would rather like a size parameter as in snprintf() so you
can give the size of the storage output points to.
<snip: Code>
All kinds of comments are welcome, regarding the code, the interface
design, the documentation, etc etc.


- I would rather aim for a standard order of the parameters,
say leading
destination, size,
followed by either
1) replacestr, source, findstr
or
2) source, replacestr, findstr

1) has the advantage that all parameters which can have special
values are gathered to the start.

- I would rather return size_t as strlen() returns size_t

- I would not "overload" the return value semantics depending
on destination -- the user cannot detect errors this way.
I'd rather settle for returning the number of bytes needed for
the "fully replaced" destination string and returning 0 on
error.
If the number of replacements is needed, use an additional
size_t* parameter.

- give a str_n_repl variant allowing to restrict the number of
replacements.
Cheers
Michael
--
E-Mail: Mine is an /at/ gmx /dot/ de address.
Dec 6 '05 #3

P: n/a
Eric Sosman <er*********@sun.com> writes:
jacob navia wrote On 12/06/05 15:41,:

#include <string.h>
char *strrepl(char *InputString, char *StringToFind,
char *Replacement, char *Output);

[...]

int strrepl(char *InputString,char *StringToFind,
char *StringToReplace,char *output)


A diagnostic is required if both the declaration
and the definition appear in the same translation unit.


What? Have you never heard of a "function prototype"? They've
been all the rage since 1989 or so. Even before that, function
declarations before definitions were, I believe, allowed.

The real problem here is the differing return types.
--
char a[]="\n .CJacehknorstu";int putchar(int);int main(void){unsigned long b[]
={0x67dffdff,0x9aa9aa6a,0xa77ffda9,0x7da6aa6a,0xa6 7f6aaa,0xaa9aa9f6,0x11f6},*p
=b,i=24;for(;p+=!*p;*p/=4)switch(0[p]&3)case 0:{return 0;for(p--;i--;i--)case+
2:{i++;if(i)break;else default:continue;if(0)case 1:putchar(a[i&15]);break;}}}
Dec 6 '05 #4

P: n/a
Ben Pfaff wrote:
Eric Sosman <er*********@sun.com> writes:
jacob navia wrote On 12/06/05 15:41,:

#include <string.h>
char *strrepl(char *InputString, char *StringToFind,
char *Replacement, char *Output);

[...]

int strrepl(char *InputString,char *StringToFind,
char *StringToReplace,char *output)


A diagnostic is required if both the declaration
and the definition appear in the same translation unit.


What? Have you never heard of a "function prototype"? They've
been all the rage since 1989 or so. Even before that, function
declarations before definitions were, I believe, allowed.

The real problem here is the differing return types.


I think it is pretty safe to assume that he was referring to the
declaration and definition that the OP presented.

Robert Gamble

Dec 6 '05 #5

P: n/a
"Michael Mair" <Mi**********@invalid.invalid> wrote in message
news:3v*************@individual.net...
jacob navia wrote:
If the Output argument is NULL, strrepl will return the space that would
be needed (including the terminating zero) for the replacement.

If Replacement is NULL and Output is not NULL, all occurrences of
StringToFind will be erased.

Returns

The strrepl function returns the needed length for the replacements if
its Output argument is NULL. If not, it returns the number of
replacements done.


I would rather like a size parameter as in snprintf() so you
can give the size of the storage output points to.


I think that wouldn't necessarily make things any better. As I imagine, you
would rarely know how much storage could be needed by the function in
advance without calling it first with NULL as the Output argument. Also, if
you knew that, for example, strlen(StringToFind)>=strlen(Replacement) then
passing the size of storage that Output points to is pointless (since you
know how much you need, you just allocate it and that's it). While I like
the overall idea, I find this size issue very inpractical and error prone (I
imagine this is one of the reasons something like this isn't in the standard
library in the first place - but there are probably many reasons far more
important than this). It might be better for str_repl to allocate the needed
space and return a pointer to it (with the proper output written to it
ofcourse).
Dec 6 '05 #6

P: n/a
jacob navia wrote:
char *strrepl(char *InputString, char *StringToFind,
char *Replacement, char *Output);


OOOOPS
That should have been:

int strrepl (...)
^^^
of course!

Excuse me for this error.
Dec 6 '05 #7

P: n/a
Robert Gamble wrote:


I think it is pretty safe to assume that he was referring to the
declaration and definition that the OP presented.

Robert Gamble


Yes, I think Eric was misled by a confusion in the declaration:
it is int strrepl, not char *strrepl, as I mistakenly wrote.

Excuse me for this error.
jacob
Dec 6 '05 #8

P: n/a
Michael Mair wrote:
jacob navia wrote:
Hi guys!

I like C because is fun. So, I wrote this function for the lcc-win32
standard library: strrepl.

I thought that with so many "C heads" around, maybe we could improve it
in a collective brainstorming session.

Let's discuss some C here, for a change :-)

Specs:
-----
Function: strrepl

Synopsis

#include <string.h>
char *strrepl(char *InputString, char *StringToFind,
^^^^^^
ITYM: int or size_t
char *Replacement, char *Output);

In order to avoid name clashes, I'd rather call the function
str_repl or strRepl or replaceSubstring.
Description

The strrepl function replaces in InputString all occurrences of
StringToFind by Replacement, writing the modified contents into the
Output string. The original input string is not modified.

Then your prototype is wrong: You want
size_t str_repl(const char* restrict InputString,
const char* StringToFind,
const char* Replacement,
char* restrict Output);
to avoid this. Or do away with the restrict if you want
to express that the original string is not modified via
InputString.
If the Output argument is NULL, strrepl will return the space that
would be needed (including the terminating zero) for the replacement.

If Replacement is NULL and Output is not NULL, all occurrences of
StringToFind will be erased.

Returns

The strrepl function returns the needed length for the replacements if
its Output argument is NULL. If not, it returns the number of
replacements done.

I would rather like a size parameter as in snprintf() so you
can give the size of the storage output points to.

<snip: Code>

All kinds of comments are welcome, regarding the code, the interface
design, the documentation, etc etc.

- I would rather aim for a standard order of the parameters,
say leading
destination, size,
followed by either
1) replacestr, source, findstr
or
2) source, replacestr, findstr

1) has the advantage that all parameters which can have special
values are gathered to the start.

- I would rather return size_t as strlen() returns size_t


Yes, this is a good remark.

- I would not "overload" the return value semantics depending
on destination -- the user cannot detect errors this way.
I'd rather settle for returning the number of bytes needed for
the "fully replaced" destination string and returning 0 on
error.
Yes, but how would the user know how much to allocate?
The problem is that the user can't know how long the result string
will be.
If the number of replacements is needed, use an additional
size_t* parameter.
I think the number of replacements is only useful for knowing
if there was any replaceements at all, i.e; != 0

- give a str_n_repl variant allowing to restrict the number of
replacements.
Cheers
Michael


Thanks for your input.
Dec 6 '05 #9

P: n/a
jacob navia wrote:
Michael Mair wrote:
jacob navia wrote:
<snip string replacement function>
- I would not "overload" the return value semantics depending
on destination -- the user cannot detect errors this way.
I'd rather settle for returning the number of bytes needed for
the "fully replaced" destination string and returning 0 on
error.


Yes, but how would the user know how much to allocate?
The problem is that the user can't know how long the result string
will be.


The user can always know the upper bound by knowing the length of the
input string, length of search string and length of replacement string
then assuming if the replacement is longer than the search that the
input string consists entirely of strings to be replaced.
If the number of replacements is needed, use an additional
size_t* parameter.


I think the number of replacements is only useful for knowing
if there was any replaceements at all, i.e; != 0


A counter example: implementing a text editor doing a search and replace
that tells the user how many instances have been replaced. I've used
such text editors and it is a nice thing to see.

I agree with Michael that the string length and count of items replaced
should be seperate returned values.
- give a str_n_repl variant allowing to restrict the number of
replacements.


The main use I see for that is to replace only the first instance.

I think being able to specify the buffer size would be good.
--
Flash Gordon
Living in interesting times.
Although my email address says spam, it is real and I read it.
Dec 7 '05 #10

P: n/a
jacob navia wrote:
Hi guys!

I like C because is fun. So, I wrote this function for the lcc-win32
standard library: strrepl.

I thought that with so many "C heads" around, maybe we could improve it
in a collective brainstorming session.

Let's discuss some C here, for a change :-)

Specs:
-----
Function: strrepl

Synopsis

#include <string.h>
char *strrepl(char *InputString, char *StringToFind,
char *Replacement, char *Output);
Description

The strrepl function replaces in InputString all occurrences of
StringToFind by Replacement, writing the modified contents into the
Output string. The original input string is not modified.

If the Output argument is NULL, strrepl will return the space that would
be needed (including the terminating zero) for the replacement.

If Replacement is NULL and Output is not NULL, all occurrences of
StringToFind will be erased.

Returns

The strrepl function returns the needed length for the replacements if
its Output argument is NULL. If not, it returns the number of
replacements done.

Code:
-----
#include <string.h>
int strrepl(char *InputString,char *StringToFind,
char *StringToReplace,char *output)
{
char *offset = NULL, *CurrentPointer = NULL;
int insertlen;
int findlen = strlen(StringToFind);
int result = 0;

if (StringToReplace)
insertlen = strlen(StringToReplace);
else
insertlen = 0;
if (output) {
if (output != InputString)
memmove(output,InputString,strlen(InputString)+1);
InputString = output;
}
else
result = strlen(InputString)+1;

while (*InputString) {
offset = strstr(!offset?InputString:CurrentPointer,StringTo Find);
if (offset == NULL)
break;
CurrentPointer = (offset + (output ? insertlen : findlen));
if (output) {
strcpy (offset, (offset + findlen));
memmove (offset + insertlen,
offset, strlen (offset) + 1);
if (insertlen)
memcpy (offset, StringToReplace, insertlen);
result++;
}
else {
result -= findlen;
result += insertlen;
}
}
return result;
}

All kinds of comments are welcome, regarding the code, the interface
design, the documentation, etc etc.

jacob


I'm late here and I apologize. Thank you Jacob for bringing up the
subject. Clipper and FoxPro (which pay my current rent) have several
fairly rich string functions. I have determined to 'copy' them to C.
This (stuff) is one of them. In xBASE we would simply assign the value
to a variable..

var1 = "Now is the time!"
var2 = stuff(var1, 8, 0, "NOT ")

...but in C we can't assign strings so I have determined to use the
destination/source construct of C string functions.

/*
Allows 0 or more charcters to be removed from a string at a
given point and 0 or more characters to be inserted at that point.
*/
char *stuff(char *dst, char *src, int beg, int rem, char *ins) {
char tmp[256];
int i, j, k;
for (i = 0; i < beg; ++i)
tmp[i] = src[i]; /* Copy the 'head' of src to tmp */
j = i + rem; /* Index for 'tail' of src */
for (k = 0; ins[k];)
tmp[i++] = ins[k++];
for (; src[j];)
tmp[i++] = src[j++];
tmp[i] = 0;
return strcpy(dst, tmp);
}

--
Joe Wright
"Everything should be made as simple as possible, but not simpler."
--- Albert Einstein ---
Dec 7 '05 #11

P: n/a
jacob navia wrote:
Yes, but how would the user know how much to allocate?
The problem is that the user can't know how long the result string
will be.


I would rather not depend on the user to allocate the memory. If it
were me, and I've done it before, I would let the function realloc() as
necessary. Of course, this is not typical C library behavior. But I
like to make my string functions behave like scripting languages as
much as possible.

The only problem with this kind of implementation is that this may
modify the pointer to the string so all other references to the string
will be invalid after the function call. And of course, realloc() may
fail so the function must also return a fail value when realloc()
fails.

Dec 7 '05 #12

P: n/a
buda wrote:
"Michael Mair" <Mi**********@invalid.invalid> wrote in message
news:3v*************@individual.net...
jacob navia wrote:
If the Output argument is NULL, strrepl will return the space that would
be needed (including the terminating zero) for the replacement.

If Replacement is NULL and Output is not NULL, all occurrences of
StringToFind will be erased.

Returns

The strrepl function returns the needed length for the replacements if
its Output argument is NULL. If not, it returns the number of
replacements done.


I would rather like a size parameter as in snprintf() so you
can give the size of the storage output points to.


I think that wouldn't necessarily make things any better. As I imagine, you
would rarely know how much storage could be needed by the function in
advance without calling it first with NULL as the Output argument. Also, if
you knew that, for example, strlen(StringToFind)>=strlen(Replacement) then
passing the size of storage that Output points to is pointless (since you
know how much you need, you just allocate it and that's it). While I like
the overall idea, I find this size issue very inpractical and error prone (I
imagine this is one of the reasons something like this isn't in the standard
library in the first place - but there are probably many reasons far more
important than this). It might be better for str_repl to allocate the needed
space and return a pointer to it (with the proper output written to it
ofcourse).


outsize = str_repl(NULL, 0, replace, source, find, NULL);
if (outsize)
{
char* outbuf = malloc(outsize);
if (outbuf) {
outsize = str_repl(outbuf, outsize, replace, source, find, &numrep);
....
}
....
}
.....

Same as snprintf() but easier to use due to the size_t return of
the necessary number of bytes.

If you want, you can of course make an allocating variant, say
astr_repl(&outbuf, outsize, ....)
Cheers
Michael
--
E-Mail: Mine is an /at/ gmx /dot/ de address.
Dec 7 '05 #13

P: n/a
jacob navia wrote:
Michael Mair wrote:
jacob navia wrote:
<snip>
Description

The strrepl function replaces in InputString all occurrences of
StringToFind by Replacement, writing the modified contents into the
Output string. The original input string is not modified.


Then your prototype is wrong: You want
size_t str_repl(const char* restrict InputString,
const char* StringToFind,
const char* Replacement,
char* restrict Output);
to avoid this. Or do away with the restrict if you want
to express that the original string is not modified via
InputString.
I expected some comment here.
If the Output argument is NULL, strrepl will return the space that
would be needed (including the terminating zero) for the replacement.

If Replacement is NULL and Output is not NULL, all occurrences of
StringToFind will be erased.

Returns

The strrepl function returns the needed length for the replacements
if its Output argument is NULL. If not, it returns the number of
replacements done.


I would rather like a size parameter as in snprintf() so you
can give the size of the storage output points to.

<snip: Code>

All kinds of comments are welcome, regarding the code, the interface
design, the documentation, etc etc.

<snip>
- I would rather return size_t as strlen() returns size_t


Yes, this is a good remark.


Unfortunately, it is the one point completely open to
debate (think of snprintf())
- I would not "overload" the return value semantics depending
on destination -- the user cannot detect errors this way.
I'd rather settle for returning the number of bytes needed for
the "fully replaced" destination string and returning 0 on
error.


Yes, but how would the user know how much to allocate?
The problem is that the user can't know how long the result string
will be.


But of course he can. Using a call to str_repl!
Really, just the same as snprintf() but better
See my reply to buda: <3v*************@individual.net>

If the number of replacements is needed, use an additional
size_t* parameter.


I think the number of replacements is only useful for knowing
if there was any replaceements at all, i.e; != 0


Nope. However, if you think so, then returning 0/non-zero
is enough (even an empty destination string takes up at
least 1 byte).
- give a str_n_repl variant allowing to restrict the number of
replacements.


Thanks for your input.


You're welcome :-)

Cheers
Michael
--
E-Mail: Mine is an /at/ gmx /dot/ de address.
Dec 7 '05 #14

P: n/a
sl*******@yahoo.com a écrit :
jacob navia wrote:
Yes, but how would the user know how much to allocate?
The problem is that the user can't know how long the result string
will be.

I would rather not depend on the user to allocate the memory. If it
were me, and I've done it before, I would let the function realloc() as
necessary. Of course, this is not typical C library behavior. But I
like to make my string functions behave like scripting languages as
much as possible.

The only problem with this kind of implementation is that this may
modify the pointer to the string so all other references to the string
will be invalid after the function call. And of course, realloc() may
fail so the function must also return a fail value when realloc()
fails.

Yes, if you enter memory allocation you open a can of
worms. You can't realloc if InputString was NOT allocated
with malloc!

The InputString could be a static buffer or a local array
This code would fail
int fn(void)
{
char buf[256];
strcpy(buf,"a sentence with a Word");
strrepl(buf,"Word","words",buf);
}
Of course within an application that uses malloc always for the strings
a realloc solution is sensible, but within a C library it is not.

jacob
Dec 7 '05 #15

P: n/a
On Tue, 06 Dec 2005 21:41:04 +0100, jacob navia wrote:
Hi guys!

I like C because is fun. So, I wrote this function for the lcc-win32
standard library: strrepl.

I thought that with so many "C heads" around, maybe we could improve it
in a collective brainstorming session.

Let's discuss some C here, for a change :-)

Specs:
-----
Function: strrepl

Synopsis

#include <string.h>
char *strrepl(char *InputString, char *StringToFind,
char *Replacement, char *Output);
I agree with others that a better return type is size_t rather than int
and that the first three parameters would be better const-qualified.
Also Replacement is a better term than StringToReplace which is used
further down - the latter is easy to confuse with the term StringToFind.
Description

The strrepl function replaces in InputString all occurrences of
StringToFind by Replacement, writing the modified contents into the
Output string. The original input string is not modified.
You could also mention that InputString must be a non-NULL pointer, and
that StringToFind must be a non-empty string since the function doesn't
check for either of these.
If the Output argument is NULL, strrepl will return the space that would
be needed (including the terminating zero) for the replacement.

If Replacement is NULL and Output is not NULL, all occurrences of
StringToFind will be erased.
Don't you think it would be better not to have to deal with that
unnecessary special-case? I found the conditionals this required in the
function distracting. Passing an empty string achieves the same result.
Returns

The strrepl function returns the needed length for the replacements if
its Output argument is NULL. If not, it returns the number of
replacements done.
Others have suggested not having a dual-meaning return; I think it's OK
since it simplifies the function and its prototype.
Code:
-----
#include <string.h>
int strrepl(char *InputString,char *StringToFind,
char *StringToReplace,char *output)
{
char *offset = NULL, *CurrentPointer = NULL;
int insertlen;
int findlen = strlen(StringToFind);
int result = 0;
All three of the above would be better as size_t.
if (StringToReplace)
insertlen = strlen(StringToReplace);
else
insertlen = 0;
if (output) {
if (output != InputString)
memmove(output,InputString,strlen(InputString)+1);

InputString = output;
The assignment of an output variable to a parameter with "Input" in its
name made it harder for me to read the code.
}
else
result = strlen(InputString)+1;

while (*InputString) {
offset = strstr(!offset?InputString:CurrentPointer,StringTo Find);
if (offset == NULL)
break;
CurrentPointer = (offset + (output ? insertlen : findlen)); if
(output) {
strcpy (offset, (offset + findlen));
* I have comments on this further down.
memmove (offset + insertlen,
offset, strlen (offset) + 1);
** and this.
if (insertlen)
memcpy (offset, StringToReplace, insertlen);
result++;
}
else {
result -= findlen;
result += insertlen;
}
}
return result;
}

All kinds of comments are welcome, regarding the code, the interface
design, the documentation, etc etc.


Your function allows for the possibility that InputString and output
alias. Unfortunately the code is lowest-common denominator for the
worst-case possibility that they do alias and that the replacement token
is longer than the token to replace.

Many optimisations are possible when neither of these conditions are
true. For example the line I've asterisked is very inefficient for
multiple matches - it copies the entire trailing part of the string for
each match. The line I've double-asterisked is also very inefficient -
it's unnecessary to call strlen as well as move the entire trailing part
of the string when the input and output don't alias.

Below is a version of a function from a previous thread [1] - based on
code and comments from Mark Haigh, Skarmandar, Dave Thompson and myself -
modified for your prototype and desired behaviour except that it /doesn't/
allow input and output to alias. I haven't used the restrict keyword
since it may be compiled under C90. It also doesn't deal with a NULL
replacement string - for that use "".

It has (commented) potential for UB on large strings that as the
implementor you no doubt would know how to avoid.

This function is about 4 times faster than yours on small strings and
about 300 times faster on large strings where there are many small
replacements - tested using the benchmarking code I wrote for the previous
thread using gcc -O2 under Linux on a P4.

So my suggestion is to deal separately with the worst-case codepath
(possibly using a version of strstr that works backwards). The
second-worst case - where input and output strings alias and the
replacement token is shorter than replaced token - can be better handled
by keeping track of how many replacements have occurred and only moving as
much of the string as is necessary on each match.

The following function contains code optimised for all other (i.e.
non-aliasing) situations.

size_t strrepl(const char *str, const char *old, const char *new, char *ret) {
char *r;
const char *p, *q;
size_t count = 0;
size_t oldlen = strlen(old);
size_t newlen = strlen(new);

if (ret == NULL) {
size_t retlen;
if (oldlen != newlen) {
for (p = str; (q = strstr(p, old)) != NULL; p = q + oldlen)
count++;
/* this is undefined if p - str > PTRDIFF_MAX */
retlen = p - str + strlen(p) + count * (newlen - oldlen);
} else
retlen = strlen(str);
return retlen + 1;
}

for (r = ret, p = str; (q = strstr(p, old)) != NULL; p = q + oldlen) {
/* this is undefined if q - p > PTRDIFF_MAX */
ptrdiff_t l = q - p;
memcpy(r, p, l);
r += l;
memcpy(r, new, newlen);
r += newlen;
count++;
}
strcpy(r, p);

return count;
}

[1] http://groups.google.com/group/comp....f5492fdf79656d

--
http://members.dodo.com.au/~netocrat
Dec 7 '05 #16

P: n/a
WOW!!!!!!!

Very nice.

The problem with strings bigger than 2GB (PTRDIFF_MAX) is not relevant
in the environment of lcc-win32. There is a 2GB limit on the 4GB
addressing space since windows uses the higher 2GB. So, that
problem is moot.

I will add code in the first part of the strrepl function
to test for the conditions you mention and call your function if
the requirements are met.

Thanks a lot for your input, it is very good.

jacob
Dec 7 '05 #17

P: n/a
"Michael Mair" <Mi**********@invalid.invalid> wrote in message
news:3v*************@individual.net...
buda wrote:
"Michael Mair" <Mi**********@invalid.invalid> wrote in message
news:3v*************@individual.net...
jacob navia wrote:

If the Output argument is NULL, strrepl will return the space that would
be needed (including the terminating zero) for the replacement.

If Replacement is NULL and Output is not NULL, all occurrences of
StringToFind will be erased.

Returns

The strrepl function returns the needed length for the replacements if
its Output argument is NULL. If not, it returns the number of
replacements done.

I would rather like a size parameter as in snprintf() so you
can give the size of the storage output points to.


I think that wouldn't necessarily make things any better. As I imagine,
you would rarely know how much storage could be needed by the function in
advance without calling it first with NULL as the Output argument. Also,
if you knew that, for example, strlen(StringToFind)>=strlen(Replacement)
then passing the size of storage that Output points to is pointless
(since you know how much you need, you just allocate it and that's it).
While I like the overall idea, I find this size issue very inpractical
and error prone (I imagine this is one of the reasons something like this
isn't in the standard library in the first place - but there are probably
many reasons far more important than this). It might be better for
str_repl to allocate the needed space and return a pointer to it (with
the proper output written to it ofcourse).


outsize = str_repl(NULL, 0, replace, source, find, NULL);
if (outsize)
{
char* outbuf = malloc(outsize);
if (outbuf) {
outsize = str_repl(outbuf, outsize, replace, source, find, &numrep);
....
}
....
}
....


That was exactly my point. You obtain the required size from the function
itself just prior to acctually calling it to do "the real work", so I don't
see the point of passing that back, since it is guaranteed that it will need
exactly that much.

However, since this is the behaviour of snprintf(), I imagine I am missing
something :) As I see it, snprintf is useful when you really want to write a
maximum of n characters (and you really want to "cut off" the rest). This
sort of usage doesn't seem likely for str_repl since you can't really know
what will be the contents of the first n characters of the generated output.
Dec 7 '05 #18

P: n/a
buda wrote:
"Michael Mair" <Mi**********@invalid.invalid> wrote in message
news:3v*************@individual.net...
buda wrote:
"Michael Mair" <Mi**********@invalid.invalid> wrote in message
news:3v*************@individual.net...

jacob navia wrote:

>If the Output argument is NULL, strrepl will return the space that would
>be needed (including the terminating zero) for the replacement.
>
>If Replacement is NULL and Output is not NULL, all occurrences of
>StringToFind will be erased.
>
>Returns
>
>The strrepl function returns the needed length for the replacements if
>its Output argument is NULL. If not, it returns the number of
>replacements done.

I would rather like a size parameter as in snprintf() so you
can give the size of the storage output points to.

I think that wouldn't necessarily make things any better. As I imagine,
you would rarely know how much storage could be needed by the function in
advance without calling it first with NULL as the Output argument. Also,
if you knew that, for example, strlen(StringToFind)>=strlen(Replacement)
then passing the size of storage that Output points to is pointless
(since you know how much you need, you just allocate it and that's it).
While I like the overall idea, I find this size issue very inpractical
and error prone (I imagine this is one of the reasons something like this
isn't in the standard library in the first place - but there are probably
many reasons far more important than this). It might be better for
str_repl to allocate the needed space and return a pointer to it (with
the proper output written to it ofcourse).


outsize = str_repl(NULL, 0, replace, source, find, NULL);
if (outsize)
{
char* outbuf = malloc(outsize);
if (outbuf) {
outsize = str_repl(outbuf, outsize, replace, source, find, &numrep);
....
}
....
}
....


That was exactly my point. You obtain the required size from the function
itself just prior to acctually calling it to do "the real work", so I don't
see the point of passing that back, since it is guaranteed that it will need
exactly that much.

However, since this is the behaviour of snprintf(), I imagine I am missing
something :) As I see it, snprintf is useful when you really want to write a
maximum of n characters (and you really want to "cut off" the rest). This
sort of usage doesn't seem likely for str_repl since you can't really know
what will be the contents of the first n characters of the generated output.


True. But you can do things like
if ( (ret = str_repl(outbuf, outsize, .....)) == 0 || ret > outsize )
{ /* error handling, reallocating, whatever */ }
with this information whereas the "no size parameter" variety
of str_repl() forces you to always correctly compute the necessary
amount of storage or use a "large enough" enough buffer.
The latter is about as safe as using gets(), the former at least
admits the danger of miscalculating the required size.
As soon as the overhead of letting str_repl compute the required
size and checking against the maximum number of bytes is too much,
you can consider rolling your own, unsafe function.

As Jacob wants to add str_repl as an implementation specific
extension to <string.h>, it is my opinion that the function must
not have a design flaw allowing for buffer overflow too easily.
If it were only a question of "is this a nice str_repl", then
I'd just caution against the possible dangers.
Cheers
Michael
--
E-Mail: Mine is an /at/ gmx /dot/ de address.
Dec 7 '05 #19

P: n/a
In article <pa****************************@dodo.com.au> Netocrat <ne******@dodo.com.au> writes:
....
If Replacement is NULL and Output is not NULL, all occurrences of
StringToFind will be erased.
Don't you think it would be better not to have to deal with that
unnecessary special-case? I found the conditionals this required in the
function distracting. Passing an empty string achieves the same result.


Perhaps, but it does not take much, see below.
The following function contains code optimised for all other (i.e.
non-aliasing) situations.
I will change it such that it will work when new == NULL:
size_t strrepl(const char *str, const char *old, const char *new, char *ret) {
char *r;
const char *p, *q;
size_t count = 0;
size_t oldlen = strlen(old); Modify: size_t newlen = strlen(new); to:
** size_t newlen; ** if (new == NULL) { new = ""; }
** newlen = strlen(new); if (ret == NULL) {
size_t retlen;
if (oldlen != newlen) {
for (p = str; (q = strstr(p, old)) != NULL; p = q + oldlen)
count++;
/* this is undefined if p - str > PTRDIFF_MAX */
retlen = p - str + strlen(p) + count * (newlen - oldlen);
} else
retlen = strlen(str);
return retlen + 1;
}

for (r = ret, p = str; (q = strstr(p, old)) != NULL; p = q + oldlen) {
/* this is undefined if q - p > PTRDIFF_MAX */
ptrdiff_t l = q - p;
memcpy(r, p, l);
r += l;
memcpy(r, new, newlen);
r += newlen;
count++;
}
strcpy(r, p);

return count;
}

[1] http://groups.google.com/group/comp....f5492fdf79656d

--
http://members.dodo.com.au/~netocrat

--
dik t. winter, cwi, kruislaan 413, 1098 sj amsterdam, nederland, +31205924131
home: bovenover 215, 1025 jn amsterdam, nederland; http://www.cwi.nl/~dik/
Dec 8 '05 #20

P: n/a
sl*******@yahoo.com wrote:
jacob navia wrote:
Yes, but how would the user know how much to allocate?
The problem is that the user can't know how long the result string
will be.


I would rather not depend on the user to allocate the memory. If it
were me, and I've done it before, I would let the function realloc() as
necessary. Of course, this is not typical C library behavior. But I
like to make my string functions behave like scripting languages as
much as possible.

The only problem with this kind of implementation is that this may
modify the pointer to the string so all other references to the string
will be invalid after the function call. [...]


Yeah, you need to go whole hog (unlike the Viega's SafeStr library
which just suffers from exactly the flaw you point out) if you are
going to do this. But it is well worth it. You improve performance,
significantly ease the use, improve your safety, and so on. So it ends
up feeling as powerful as a scripting language, and yet delivers
performance that's even *higher* than what the C library delivers.

You can see for yourself with "the Better String Library" (link below)
which, by the way, has an aliasing-safe, in-place, high performance
"find and replace" string function.

--
Paul Hsieh
http://www.pobox.com/~qed/
http://bstring.sf.net/

Dec 8 '05 #21

P: n/a
On Wed, 07 Dec 2005 17:14:45 +0100, jacob navia wrote:
The problem with strings bigger than 2GB (PTRDIFF_MAX) is not relevant
in the environment of lcc-win32.
I've left the comments in the code for comp.lang.c purposes.
I will add code in the first part of the strrepl function to test for
the conditions you mention and call your function if the requirements
are met.


We can do better than that. I hinted at how but got inspired to implement
it.

The second-hardest scenario (input and output pointers alias; replacement
token shorter than or equal to replaced token) can be dealt with easily by
modifying the function I posted to use memmove instead of memcpy in one of
the loop body calls, and at the end instead of strcpy.

The worst-case scenario (as above but replacement token longer than
replaced token) can be dealt with using a reverse strstr function. I've
implemented a naive portable version but as the compiler author you may be
able to improve on it using asm tricks. Anyhow gcc optimises it pretty
well.

So now every code-path in the function is avoiding redundant operations.
Even for worst-case scenario with the non-library str_rev_str
implementation the new function runs about 150 times faster than the
original for large strings with many small replacements.

In response to Dik T. Winter: yes, adding NULL-handling is trivial, but
IMO it unnecessarily clutters the code and an empty replacement string
is best represented by "" alone. This is consistent with other string
library functions.

Mildly tested:

/** A version of strstr that works in reverse - starting at string end and
* searching towards the beginning.
*
* strend and tokend must point to the last char before the terminating nul,
* not to the nul itself.
*
* Returns NULL on not found, otherwise a pointer to the last char of tok
* within str ("last char" with the above meaning).
*/
const char *str_rev_str(const char *strend, const char *strstart,
const char *tokend, const char *tokstart) {
const char *t, *last, *p;

for (p = strend; ; p = last - 1) {
for (; *p != *tokend; p--) {
if (p == strstart)
return NULL;
}
last = p;
t = tokend;
do {
if (t == tokstart) {
/* this is undefined if tokend - tokstart > PTRDIFF_MAX */
return p + (tokend - tokstart);
} else if (p == strstart)
return NULL;
} while (*--p == *--t);
if (last == strstart)
return NULL;
}
}

/** Call only when the string is being modified in-place and newlen > oldlen
*/
size_t repl_inplace_rev(char *str, const char *old, const char *new,
size_t oldlen, size_t newlen, size_t orglen, size_t retlen) {
const char *oldend = old + oldlen - 1; size_t count = 0;
char *r = str + retlen;
const char *q, *p = str + orglen - 1;

*r = '\0';
for(; (q = str_rev_str(p, str, oldend, old)) != NULL; p = q - oldlen) {
/* this is undefined if p - q > PTRDIFF_MAX */
ptrdiff_t l = p - q;
count++;
memmove(r - l, q + 1, l);
r -= l;
memcpy(r - newlen, new, newlen);
r -= newlen;
if (q - str < oldlen)
/* don't drop off the beginning of the string when there's a
* match at the beginning */
break;
}

return count;
}

size_t repl_get_lengths(const char *str, const char *old, size_t oldlen,
size_t newlen, size_t *orglen)
{
const char *p, *q;
size_t retlen;

if (oldlen != newlen) {
size_t count = 0;
for (p = str; (q = strstr(p, old)) != NULL; p = q + oldlen)
count++;
/* this is undefined if p - str > PTRDIFF_MAX */
*orglen = p - str + strlen(p);
retlen = *orglen + count * (newlen - oldlen);
} else
retlen = *orglen = strlen(str);

return retlen;
}

size_t str_repl(const char *str, const char *old, const char *new, char *ret) {
char *r;
const char *p, *q;
size_t count = 0;
size_t oldlen = strlen(old);
size_t newlen = strlen(new);

if (ret == NULL || (str == ret && newlen > oldlen)) {
size_t orglen;
size_t retlen = repl_get_lengths(str, old, oldlen, newlen, &orglen);
if (ret == NULL)
return retlen + 1;
count = repl_inplace_rev(ret, old, new, oldlen, newlen, orglen, retlen);
} else {
for (r = ret, p = str; (q = strstr(p, old)) != NULL; p = q + oldlen) {
/* this is undefined if q - p > PTRDIFF_MAX */
ptrdiff_t l = q - p;
/* when ret can't alias str, can use memcpy instead */
memmove(r, p, l);
r += l;
memcpy(r, new, newlen);
r += newlen;
count++;
}
/* when ret can't alias str, can instead use strcpy(r, p); */
memmove(r, p, strlen(p) + 1);
}
return count;
}

--
http://members.dodo.com.au/~netocrat
Dec 8 '05 #22

P: n/a
On Thu, 08 Dec 2005 02:56:09 +0000, Netocrat wrote:
const char *str_rev_str(const char *strend, const char *strstart,


More correctly, str_end and str_start.

--
http://members.dodo.com.au/~netocrat
Dec 8 '05 #23

P: n/a
In article <pa****************************@dodo.com.au> Netocrat <ne******@dodo.com.au> writes:
....
In response to Dik T. Winter: yes, adding NULL-handling is trivial, but
IMO it unnecessarily clutters the code and an empty replacement string
is best represented by "" alone. This is consistent with other string
library functions.


It indeed is consistent. But what bothers me all the time is the
programs that crash because somebody uses NULL in stead of an empty
string somewhere. For the standard library function I do understand
why NULL is not accepted for an empty string. Why use an empty string
for those functions at all? Can you name me a single string library
function that makes sense to use with the empty string constant ""?
--
dik t. winter, cwi, kruislaan 413, 1098 sj amsterdam, nederland, +31205924131
home: bovenover 215, 1025 jn amsterdam, nederland; http://www.cwi.nl/~dik/
Dec 8 '05 #24

P: n/a
On Thu, 08 Dec 2005 03:31:14 +0000, Dik T. Winter wrote:
In article <pa****************************@dodo.com.au> Netocrat
<ne******@dodo.com.au> writes: ...
> In response to Dik T. Winter: yes, adding NULL-handling is trivial,
> but IMO it unnecessarily clutters the code and an empty replacement
> string is best represented by "" alone. This is consistent with
> other string library functions.
It indeed is consistent. But what bothers me all the time is the
programs that crash because somebody uses NULL in stead of an empty
string somewhere.


Yes, safety is the only argument I can see for it. And performance is
unlikely to be much of a counter-argument - at least for strrepl.
For the standard library function I do understand why NULL is not
accepted for an empty string. Why use an empty string for those
functions at all? Can you name me a single string library function that
makes sense to use with the empty string constant ""?


I'm not sure about "makes sense" - they are redundant - but "has
reasonable meaning", yes:

strcpy(str, "");
strcat(str, "");

This one arguably makes more sense:

strcmp(str, "");

although *str != '\0' is simpler.

--
http://members.dodo.com.au/~netocrat
Dec 8 '05 #25

P: n/a
Netocrat wrote:
On Wed, 07 Dec 2005 17:14:45 +0100, jacob navia wrote:
The problem with strings bigger than 2GB (PTRDIFF_MAX) is not relevant
in the environment of lcc-win32.


I've left the comments in the code for comp.lang.c purposes.
I will add code in the first part of the strrepl function to test for
the conditions you mention and call your function if the requirements
are met.


We can do better than that. I hinted at how but got inspired to implement
it.


Your idea has a problem:

char out[1024];
size_t l = str_repl ("ababa", "aba", "cccc", out);

This causes an expand, which therefore will invoke your reverse scan
and replace algorithm. However, as you can see, a correct foward
replace should result in:

"ccccba"

but your implementation will output:

"abcccc"

--
Paul Hsieh
http://www.pobox.com/~qed/
http://bstring.sf.net/

Dec 8 '05 #26

P: n/a
in comp.lang.c i read:
I like C because is fun. So, I wrote this function for the lcc-win32
standard library: strrepl.


any chance you will stop invading the standard namespace with your
extensions?

otherwise, and not counting bugs in the code, it sounds like a fine
function to have in one's personal library.

--
a signature
Dec 8 '05 #27

P: n/a
On 2005-12-08, those who know me have no need of my name <no****************@usa.net> wrote:
in comp.lang.c i read:
I like C because is fun. So, I wrote this function for the lcc-win32
standard library: strrepl.
any chance you will stop invading the standard namespace with your
extensions?


It's the implementation-reserved namespace, not the standard one. It's
no worse than posix strdup()
otherwise, and not counting bugs in the code, it sounds like a fine
function to have in one's personal library.

Dec 9 '05 #28

P: n/a
On Thu, 08 Dec 2005 12:16:01 -0800, websnarf wrote:
[...]
Your idea has a problem:

char out[1024];
size_t l = str_repl ("ababa", "aba", "cccc", out);

This causes an expand, which therefore will invoke your reverse scan
and replace algorithm. However, as you can see, a correct foward
replace should result in:

"ccccba"

but your implementation will output:

"abcccc"


Ack, good catch. It also requires two search iterations through the
string where jacob's original requires only one: when making a single
replacement, the original function can be slightly faster on my machine.

Another approach that solves both of these problems is recursion. The
depth could be limited if that's a concern - with small penalties to
performance and code complexity. As it is the function completes even
faster on my machine than the reverse scan approach.

Aside from recursion, this code adds a couple of minor optimisations in
the main function to call memmove conditionally:

size_t repl_get_len(const char *str, const char *old, size_t oldlen,
size_t newlen)
{
const char *p, *q;
size_t retlen;

if (oldlen != newlen) {
size_t count = 0;
for (p = str; (q = strstr(p, old)) != NULL; p = q + oldlen)
count++;
/* this is undefined if p - str > PTRDIFF_MAX */
retlen = p - str + strlen(p) + count * (newlen - oldlen);
} else
retlen = strlen(str);

return retlen;
}

/** Call only when the string is being modified in-place and newlen > oldlen
*/
static void str_repl_recurs(char *str, const char *old, const char *new,
size_t oldlen, size_t newlen, size_t *count)
{
char *p;
size_t count_org = *count;
size_t diff = newlen - oldlen;

if ((p = strstr(str, old)) == NULL) {
if (count_org > 0)
memmove(str + diff * count_org, str, strlen(str) + 1);
} else {
(*count)++;
str_repl_recurs(p + oldlen, old, new, oldlen, newlen, count);
if (count_org > 0)
memmove(str + diff * count_org, str, p - str);
memcpy(p + diff * count_org, new, newlen);
}
}

size_t str_repl(const char *str, const char *old, const char *new, char *ret) {
size_t count = 0;
size_t oldlen = strlen(old);
size_t newlen = strlen(new);

if (ret == NULL) {
return repl_get_len(str, old, oldlen, newlen) + 1;
} else if (str == ret && newlen > oldlen) {
str_repl_recurs(ret, old, new, oldlen, newlen, &count);
} else {
char *r;
const char *p, *q;
for (r = ret, p = str; (q = strstr(p, old)) != NULL; p = q + oldlen) {
/* this is undefined if q - p > PTRDIFF_MAX */
ptrdiff_t l = q - p;
if (count > 0 || str != ret) /* to optimise; can be removed */
memmove(r, p, l);
r += l;
memcpy(r, new, newlen);
r += newlen;
count++;
}
if (count > 0 || str != ret) /* to optimise; can be removed */
memmove(r, p, strlen(p) + 1);
}
return count;
}

--
http://members.dodo.com.au/~netocrat
Dec 9 '05 #29

P: n/a
Netocrat <ne******@dodo.com.au> wrote:
On Thu, 08 Dec 2005 03:31:14 +0000, Dik T. Winter wrote:
For the standard library function I do understand why NULL is not
accepted for an empty string. Why use an empty string for those
functions at all? Can you name me a single string library function that
makes sense to use with the empty string constant ""?


I'm not sure about "makes sense" - they are redundant - but "has
reasonable meaning", yes:

strcpy(str, "");
strcat(str, "");


They don't make sense with empty string _constants_, no. However,
strcpy() cannot know whether it got passed a string variable or a string
constant. Copying a string variable which may or may not be empty
depending on user input (e.g., a "middle name" field for personal data)
makes all the sense in the world.
Making a null pointer equal to an empty string - effectively, passing a
"variable" which is always empty, not depending on user input, does not
make sense, though.

Richard
Dec 9 '05 #30

P: n/a
Richard Bos wrote:
Netocrat <ne******@dodo.com.au> wrote:
On Thu, 08 Dec 2005 03:31:14 +0000, Dik T. Winter wrote:
For the standard library function I do understand why NULL is not
accepted for an empty string. Why use an empty string for those
functions at all? Can you name me a single string library function that
makes sense to use with the empty string constant ""? I'm not sure about "makes sense" - they are redundant - but "has
reasonable meaning", yes:

strcpy(str, "");
strcat(str, "");


They don't make sense with empty string _constants_, no. However,
strcpy() cannot know whether it got passed a string variable or a string
constant. Copying a string variable which may or may not be empty
depending on user input (e.g., a "middle name" field for personal data)
makes all the sense in the world.


#define BUILD_TYPE ""
where other possible values include "alpha" and "beta".

/* Stuff building version information in to a string */
strcat(ver_str, BUILD_TYPE);

if (strcmp(BUILD_TYPE,"alpha") == 0) {
/* Warn user it is an alpha build */
}

There are, of course, other ways to achieve this, but it does at least
make some sense.

I'm sure there are other situations where an external (to your piece of
the development) header file defines a string with #define that, under
some situations or building on some machines, might be an empty string.
Making a null pointer equal to an empty string - effectively, passing a
"variable" which is always empty, not depending on user input, does not
make sense, though.


Well, in the above example you could have
#define BUILD_TYPE NULL
but this would only work if the string routines were defined to handle
null pointers appropriately.
--
Flash Gordon
Living in interesting times.
Although my email address says spam, it is real and I read it.
Dec 9 '05 #31

P: n/a
In article <43***************@news.xs4all.nl> rl*@hoekstra-uitgeverij.nl (Richard Bos) writes:
Netocrat <ne******@dodo.com.au> wrote:
On Thu, 08 Dec 2005 03:31:14 +0000, Dik T. Winter wrote:
For the standard library function I do understand why NULL is not
accepted for an empty string. Why use an empty string for those
functions at all? Can you name me a single string library function that
makes sense to use with the empty string constant ""?


I'm not sure about "makes sense" - they are redundant - but "has
reasonable meaning", yes:

strcpy(str, "");
strcat(str, "");


They don't make sense with empty string _constants_, no. However,
strcpy() cannot know whether it got passed a string variable or a string
constant. Copying a string variable which may or may not be empty
depending on user input (e.g., a "middle name" field for personal data)
makes all the sense in the world.
Making a null pointer equal to an empty string - effectively, passing a
"variable" which is always empty, not depending on user input, does not
make sense, though.


But it does make sense in a function as discussed here.
--
dik t. winter, cwi, kruislaan 413, 1098 sj amsterdam, nederland, +31205924131
home: bovenover 215, 1025 jn amsterdam, nederland; http://www.cwi.nl/~dik/
Dec 9 '05 #32

P: n/a
On Fri, 9 Dec 2005 03:14:15 +0000 (UTC), in comp.lang.c , Jordan Abel
<jm****@purdue.edu> wrote:
On 2005-12-08, those who know me have no need of my name <no****************@usa.net> wrote:
in comp.lang.c i read:
I like C because is fun. So, I wrote this function for the lcc-win32
standard library: strrepl.


any chance you will stop invading the standard namespace with your
extensions?


It's the implementation-reserved namespace, not the standard one. It's
no worse than posix strdup()


.... and arguably, he's allowed to do this ,because ie is writing an
implementation.

----== Posted via Newsfeeds.Com - Unlimited-Unrestricted-Secure Usenet News==----
http://www.newsfeeds.com The #1 Newsgroup Service in the World! 120,000+ Newsgroups
----= East and West-Coast Server Farms - Total Privacy via Encryption =----
Dec 10 '05 #33

P: n/a
Mark McIntyre a écrit :
On Fri, 9 Dec 2005 03:14:15 +0000 (UTC), in comp.lang.c , Jordan Abel
<jm****@purdue.edu> wrote:

On 2005-12-08, those who know me have no need of my name <no****************@usa.net> wrote:
in comp.lang.c i read:
I like C because is fun. So, I wrote this function for the lcc-win32
standard library: strrepl.

any chance you will stop invading the standard namespace with your
extensions?


It's the implementation-reserved namespace, not the standard one. It's
no worse than posix strdup()

... and arguably, he's allowed to do this ,because ie is writing an
implementation.

----== Posted via Newsfeeds.Com - Unlimited-Unrestricted-Secure Usenet News==----
http://www.newsfeeds.com The #1 Newsgroup Service in the World! 120,000+ Newsgroups
----= East and West-Coast Server Farms - Total Privacy via Encryption =----


Yes, the standard explicitely allows for implementations
to define new "strxxx" functions.
Dec 10 '05 #34

P: n/a
Dik T. Winter wrote:
Richard Bos writes:

[string arguments in standard library functions]
> Making a null pointer equal to an empty string - effectively, passing
> a "variable" which is always empty, not depending on user input, does
> not make sense, though.


But it does make sense in a function [strrepl] as discussed here.


When designing a relational database table it's IMO good practice to
minimise the number of columns that may be NULL[*]. I view the string
functions in the same way. A null pointer is not a string, and should
not be accepted in place of one.

You've pointed out a reasonable safety argument. This goes both ways
though: since the Standard doesn't require a null pointer to be acceptable
as an empty string value even where it could be, allowing the programmer
to do so for this individual function may encourage an unsafe habit.
[*] the meaning of NULL is different in this context but it's similar
enough for the analogy to hold.

--
http://members.dodo.com.au/~netocrat
Dec 10 '05 #35

P: n/a
On Sat, 10 Dec 2005 11:41:23 GMT, Netocrat <ne******@dodo.com.au>
wrote:
<snip>
When designing a relational database table it's IMO good practice to
minimise the number of columns that may be NULL[*]. I view the string
functions in the same way. A null pointer is not a string, and should
not be accepted in place of one.
Agree here, mostly.
<snip>[*] the meaning of NULL is different in this context but it's similar
enough for the analogy to hold.


Although I once had trouble explaining to someone the difference in a
C API between a pointer to a variable used to indicate whether a value
is (SQL) NULL or not, and a null pointer to indicator which cannot so
indicate and thus gives an error for (SQL) NULL value.
- David.Thompson1 at worldnet.att.net
Dec 19 '05 #36

This discussion thread is closed

Replies have been disabled for this discussion.