[alt.sources.wanted] What is strdup

afc@shibaya.lonestar.org (Augustine Cano) (02/14/91)

While attempting to compile the recently posted procmail package, I could
not fine strdup() in any library, on any of the machines I have access to.

If anybody has a copy they can send, I'd really appreciate it.  Failing
that, a man page or description would certainly help.

Thanks.

-- 
Augustine Cano		INTERNET: afc@shibaya.lonestar.org
			UUCP:     ...!{ernest,egsner}!shibaya!afc

jik@athena.mit.edu (Jonathan I. Kamens) (02/15/91)

(Written for ANSI C.)

#include <stdlib.h>

/* strdup -- duplicate string in malloc'd memory */

char *strdup(char *str)
{
	char *new, *ptr;

	if (! str)
		return(0);

	new = (char *) malloc(strlen(str) + 1);
	if (! new)
		return(0);

	for (ptr = new; *ptr++ = *str++; ) /* empty loop body */;

	return(new);
}

-- 
Jonathan Kamens			              USnail:
MIT Project Athena				11 Ashford Terrace
jik@Athena.MIT.EDU				Allston, MA  02134
Office: 617-253-8085			      Home: 617-782-0710

emv@ox.com (Ed Vielmetti) (02/15/91)

In article <1991Feb14.050716.9501@shibaya.lonestar.org> afc@shibaya.lonestar.org (Augustine Cano) writes:

   While attempting to compile the recently posted procmail package, I could
   not fine strdup() in any library, on any of the machines I have access to.

Henry Spencer's strings library is ftp'able from cs.toronto.edu. 

-- 
 Msen	Edward Vielmetti
/|---	moderator, comp.archives
	emv@msen.com

cbrown@eeserv1.ic.sunysb.edu (Charles T Brown) (02/17/91)

In article <1991Feb14.050716.9501@shibaya.lonestar.org> afc@shibaya.lonestar.org (Augustine Cano) writes:
>While attempting to compile the recently posted procmail package, I could
>not fine strdup() in any library, on any of the machines I have access to.
>
>If anybody has a copy they can send, I'd really appreciate it.  Failing
>that, a man page or description would certainly help.
>
>Thanks.

Well, having learned C with Microsoft C, I looked it up.

Basically:

char * strdup (s)

char * s;
{
	char * rets;

	rets=malloc (sizeof (char) * strlen (s));

	strcpy (rets, s);

	return rets;
}


In other words, it just duplicates the string.	

>
>-- 
>Augustine Cano		INTERNET: afc@shibaya.lonestar.org
>			UUCP:     ...!{ernest,egsner}!shibaya!afc
--Titus

-- 
"Never put off until tomorrow, that which can be done the day after tomorrow"
          -- C. Titus Brown, anonymous student, brown@max.physics.sunysb.edu

                UNIX is good, you say?  Which UNIX, say I!

rearl@spiff.ai.mit.edu (Robert Earl) (02/17/91)

In article <1991Feb17.045913.17126@sbcs.sunysb.edu> cbrown@eeserv1.ic.sunysb.edu (Charles T Brown) writes:

|   In article <1991Feb14.050716.9501@shibaya.lonestar.org> afc@shibaya.lonestar.org (Augustine Cano) writes:
|   >While attempting to compile the recently posted procmail package, I could
|   >not fine strdup() in any library, on any of the machines I have access to.
|
|   char * strdup (s)
|
|   char * s;
|   {
|	   char * rets;
|
|	   rets=malloc (sizeof (char) * strlen (s));

This is wrong; you haven't allocated enough space for the whole
string, which is terminated by a final ASCII NUL ('\0').  It should be
"strlen (s) + 1".

It'd also be nice to cast the return value of malloc to (char *) and
check for NULL, especially on architectures that won't necessarily
catch writes to a zero pointer.

--
robert earl
rearl@geech.ai.mit.edu

jeff@onion.rain.com (Jeff Beadles) (02/18/91)

In <1991Feb17.045913.17126@sbcs.sunysb.edu> cbrown@eeserv1.ic.sunysb.edu
 (Charles T Brown) writes:
>
>Well, having learned C with Microsoft C, I looked it up.
>
>Basically:
>
>char * strdup (s)
>
>char * s;
>{
>	char * rets;
>
>	rets=malloc (sizeof (char) * strlen (s));
>
>	strcpy (rets, s);
>
>	return rets;
>}

Please folks, if you're going to answer a question, please do it correctly. 
There are two rather serious bugs with this function.

1)  If malloc returns an error, it's ignored and the program blindly continues.

2)  You're not malloc'ing enough space for the string!  You **MUST** malloc
strlen(str) + 1!  The +1 is for the trailing null that is added to the end
of every strcpy'ed string.


Actually, malloc and strlen should also be declared, but that's possibly
different for various systems.

Strcpy could also return an error, but I don't think that I've ever seen
someone check for it. :-)

Here's an updated and working version of strdup()

char *
strdup (s)
char *s;
{
	static char *rets;
	extern char *malloc();	/* Might be extern void *malloc(); */
	extern int strlen();

	rets=malloc (sizeof (char) * strlen (s) + sizeof(char) );

	/* Malloc failed.  Oops! */
	if (!rets) {
		return((char *)0);
	}

	(void) strcpy (rets, s);

	return (rets);
}


	-Jeff
-- 
Jeff Beadles		jeff@onion.rain.com

dag@persoft.com (Daniel A. Glasser) (02/18/91)

In article <1991Feb17.164731.7564@onion.rain.com> jeff@onion.rain.com (Jeff Beadles) writes:
>Here's an updated and working version of strdup()
>
>char *
>strdup (s)
>char *s;
>{
>	static char *rets;
>	extern char *malloc();	/* Might be extern void *malloc(); */
>	extern int strlen();
>
>	rets=malloc (sizeof (char) * strlen (s) + sizeof(char) );
>
>	/* Malloc failed.  Oops! */
>	if (!rets) {
>		return((char *)0);
>	}
>
>	(void) strcpy (rets, s);
>
>	return (rets);
>}

Two minor nits...

Nit #1:	Why is rets static?  Is there any reason to not leave it as automatic?
        The value is not used between calls, and why waste data space when the
	stack is available for these purposes?  I'd suggest leaving the "static"
	off.

Nit #2:	You should simplify your expression in the "malloc()", that is,
		sizeof(char) * strlen(foo) + sizeof(char)
	could be written
		sizeof(char) * (strlen(foo) + 1)
	I realize that this doesn't make it any less work for the CPU
	(both are 1 add and 1 multiply), but to the latter form makes
	it clearer what is being done (allocating enough space for
	strlen(foo)+1 chars).

Also note that some compilers will complain about the extern function
declarations within function scope.  Declarations of these functions should
be left to header files (if they are declared in header files) so as not to
get in trouble with ANSI-C compliant implementations.

A shorter version (assuming declarations of malloc(), strlen(), and strcpy(),
and a definition for NULL in some header file or preceeding this function
in the source file is:

char *strdup(orig)	/* Allocate a new copy of a string 	*/
char *orig;		/* a pointer to the original string 	*/
{
	char *copy;	/* where we keep the copy.		*/

	if (orig == (char *)NULL)	/* If the original is NULL	*/
		return (char *)NULL;	/* so is the result.		*/

	if (copy = malloc((strlen(orig) + 1) * sizeof(char)))
		strcpy(copy, orig);	/* if malloc() worked, copy the	*/
					/* string data.			*/
	return copy;			/* return the result of malloc() */
} /* end of strdup() */

I did add one more error check, and I used some shorthand (the assignment
within the if()) that some people may take exception to, however this is
just about as efficient (code wise) as you can get and still insure
robust behavior of the function.  If you drop the NULL check on the
original, you can have it even smaller but at the risk that the strcpy
or strlen call will die a horrible death.
-- 
          Daniel A. Glasser  |  Persoft, Inc.  |  dag@persoft.com
                "Their brains were small, and they died."

jeff@onion.rain.com (Jeff Beadles) (02/19/91)

 In <1991Feb18.154159.430@persoft.com> dag@persoft.com (Daniel Glasser) writes:
 >In article <1991Feb17.164731.7564@onion.rain.com> I wrote:
 >>Here's an updated and working version of strdup()
 >>
 >>char *
 >>strdup (s)
 >>char *s;
 >>{
 >>	static char *rets;
 >>	extern char *malloc();	/* Might be extern void *malloc(); */
 >>	extern int strlen();
 >>
 >>	rets=malloc (sizeof (char) * strlen (s) + sizeof(char) );
 >>
 >>	/* Malloc failed.  Oops! */
 >>	if (!rets) {
 >>		return((char *)0);
 >>	}
 >>
 >>	(void) strcpy (rets, s);
 >>
 >>	return (rets);
 >>}
 >
 >Two minor nits...
 >
 >Nit #1:	Why is rets static?  Is there any reason to not leave it as automatic?
 >        The value is not used between calls, and why waste data space when the
 >	stack is available for these purposes?  I'd suggest leaving the "static"
 >	off.
 
A creature of habit, I suppose.  I've been bitten too often when I return
something from a function that isn't static.  (int's, for example.)  For this
case, it really doesn't matter.

It's kinda like the braces around the malloc failure.  They're not technically
required, but it's not a bad habit. :-)
 
 >Nit #2:	You should simplify your expression in the "malloc()", that is,
 >		sizeof(char) * strlen(foo) + sizeof(char)
 >	could be written
 >		sizeof(char) * (strlen(foo) + 1)
 
 >	I realize that this doesn't make it any less work for the CPU
 >	(both are 1 add and 1 multiply), but to the latter form makes
 >	it clearer what is being done (allocating enough space for
 >	strlen(foo)+1 chars).
 
Untrue.  What if sizeof(char) != 1?  Yours will break, and mine will work.
 
{note:  I don't personally know of places where this isn't true, but then
        again, some people think that sizeof (int) == sizeof (char *) :-}

Also, sizeof() isn't taking anything extra.  It's changed to a '1' by the
COMPILER.  Overall, I stand by my choice of + sizeof(char).



I wrote this as an example for folks needing the functionality, not as a
finely-tuned piece of code.  You're more than welcome to improve on it.

	-Jeff
-- 
Jeff Beadles		jeff@onion.rain.com

jik@athena.mit.edu (Jonathan I. Kamens) (02/19/91)

(Note the Followup-To.)

In article <1991Feb19.004526.16033@onion.rain.com> jeff@onion.rain.com (Jeff Beadles) writes:

    In <1991Feb18.154159.430@persoft.com> dag@persoft.com (Daniel Glasser) writes:
    > [he asks why the temporary char *ret inside strdup is declared static]

   A creature of habit, I suppose.  I've been bitten too often when I return
   something from a function that isn't static.  (int's, for example.)  For this
   case, it really doesn't matter.

I would suggest that if you can't tell the difference between a value
that is safe to return from a function, and a value that is not,
you're better off letting other people post code to the net.  I posted
a working version of strdup() the same day the question was asked, and
yet we have all these people posting inferior versions (That's not my
ego speaking, for all of you who are getting ready to pounce on your
"F" key for flaming me about saying, "My code is better than yours!"
That's just simple fact.  The version I posted had no errors; if you
think it did, feel free to point them out.).

Yes, I know there are lags in news transmission, and it's quite
possible that you didn't see my posting before posting yours.  I
wouldn't be mentioning the duplication at all if it weren't for the
fact that your code was wrong.

You should not declare variables static when they don't have to be
static.  Code which declares a variable static when that variable has
absolutely no reason whatsover to be static is wrong.

   It's kinda like the braces around the malloc failure.  They're not technically
   required, but it's not a bad habit. :-)

Braces around a one-line "if" block are good programming because they
don't affect the compiled code, and because they will save you from
problems if you change things later so that there is more than one
statement in the body of the "if," and because if the statement is
actually a macro that has multiple statements in it, the braces
protect you from any dangerous results.

On the other hand, declaring a variable static when it doesn't have to
be *does* affect the compiler output, by keeping a variable in memory
all the time when it doesn't have to be.  Furthermore, unless you plan
to seriously change the functionality of strdup() at some point in the
future, there is no chance that that variable will ever need to be
static, so there is no "preventative" excuse to make it static.

    >Nit #2:	You should simplify your expression in the "malloc()", that is,
    >		sizeof(char) * strlen(foo) + sizeof(char)
    >	could be written
    >		sizeof(char) * (strlen(foo) + 1)

   Untrue.  What if sizeof(char) != 1?  Yours will break, and mine will work.

You're wrong.  Both expressions above will result in the proper value,
whether sizeof(char) is 1 or not.  Your expression takes the number of
characters in the string, multiplies it by the size of a character,
and adds the size of a character.  The other suggested expression
takes the number of characters in the string, adds 1 to it, and
multiples the result by the size of a character.  The fact that these
will result in the same value should be obvious.  And, incidentally, I
agree with the previous poster that the latter expression is clearer
than the former.

I'm sorry if I'm coming down a bit hard on you.  I guess I'm taking
out on you all the frustration I've been feeling for the past three
days, watching people post wrong or incomplete answers to a solved
problem with the solution has already been posted.  It's a bit
irritating.

Jonathan Kamens			              USnail:
MIT Project Athena				11 Ashford Terrace
jik@Athena.MIT.EDU				Allston, MA  02134
Office: 617-253-8085			      Home: 617-782-0710

guy@auspex.auspex.com (Guy Harris) (02/20/91)

>I did add one more error check, and I used some shorthand (the assignment
>within the if()) that some people may take exception to, however this is
>just about as efficient (code wise) as you can get

Most compilers these days should be smart enough to generate equally
good code for

	if (foo = bar())
		do something;

and

	foo = bar;
	if (foo)
		do something;

>and still insure robust behavior of the function.  If you drop the NULL
>check on the original, you can have it even smaller but at the risk
>that the strcpy or strlen call will die a horrible death.

There is only such a risk if you don't check for null pointers before
doing a "strdup()".  The version of "strdup()" in the S5R3 source - from
which the version is many UNIX implementations is derived - doesn't do
the check for you.  The version in 4.3-reno doesn't do so either.  Given
that, correct code doesn't pass NULL pointers to "strdup()"....

Speaking of the 4.3-reno version, here it is - whether you consider the
use of "bcopy()" rather than "strcpy()" the Right Thing or not is up to
you ("memcpy()" could be used instead, if you have it and don't have
"bcopy()"):

/*
 * Copyright (c) 1988 The Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms are permitted
 * provided that: (1) source distributions retain this entire copyright
 * notice and comment, and (2) distributions including binaries display
 * the following acknowledgement:  ``This product includes software
 * developed by the University of California, Berkeley and its contributors''
 * in the documentation or other materials provided with the distribution
 * and in all advertising materials mentioning features or use of this
 * software. Neither the name of the University nor the names of its
 * contributors may be used to endorse or promote products derived
 * from this software without specific prior written permission.
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)strdup.c	5.3 (Berkeley) 6/1/90";
#endif /* LIBC_SCCS and not lint */

#include <sys/types.h>
#include <stddef.h>
#include <string.h>


char *
strdup(str)
	char *str;
{
	int len;
	char *copy, *malloc();

	len = strlen(str) + 1;
	if (!(copy = malloc((u_int)len)))
		return((char *)NULL);
	bcopy(str, copy, len);
	return(copy);
}

6sigma2@polari.UUCP (Brian Matthews) (02/20/91)

This has little to do with strdup any more, but there seem to be some
fairly serious C misconceptions herein, hence pointing followups to
comp.lang.c.

In article <1991Feb19.004526.16033@onion.rain.com> jeff@onion.rain.com (Jeff Beadles) writes:
| In <1991Feb18.154159.430@persoft.com> dag@persoft.com (Daniel Glasser) writes:
| >Nit #1:	Why is rets static?
|A creature of habit, I suppose.  I've been bitten too often when I return
|something from a function that isn't static.  (int's, for example.)  For this
|case, it really doesn't matter.

The function return value should never have to be static.  What may have
to be static is the area pointed to by a returned pointer.  A scalar
(long, double, etc.) shouldn't have to be static, unless you have a
very seriously broken compiler.

|It's kinda like the braces around the malloc failure.  They're not technically
|required, but it's not a bad habit. :-)

The braces around the malloc failure are mostly style, and have no affect
on the final executable.  Making things static does.  Static variables
take up space in the final executable on disk, must be read into
memory, and take up memory all the time, even if they're never used.
Automatics don't take disk space, and only use memory when their
enclosing function or a children thereof are active.  Making variables
static that don't have to be *is* a bad habit.

| >Nit #2:	You should simplify your expression in the "malloc()", that is,
| >		sizeof(char) * strlen(foo) + sizeof(char)
| >	could be written
| >		sizeof(char) * (strlen(foo) + 1)
|Untrue.  What if sizeof(char) != 1?  Yours will break, and mine will work.

Last I looked, the distributive law still holds (ignoring overflow and
other hard stuff :-)).  Multiply the second expression and you'll
see that it's (at least algebraically) equivalent to the first expression.
Either will work for the purpose at hand.
-- 
Brian L. Matthews	6sigma2@polari.UUCP

fischer@iesd.auc.dk (Lars P. Fischer) (02/21/91)

>>>>> dag@persoft.com (Daniel Glasser) writes:

Daniel>Nit #2: You should simplify your expression in the "malloc()", that is,
Daniel>		sizeof(char) * strlen(foo) + sizeof(char)
Daniel>	  could be written
Daniel>		sizeof(char) * (strlen(foo) + 1)

>>>>> jeff@onion.rain.com (Jeff Beadles) then said:

Jeff> Untrue.  What if sizeof(char) != 1?  Yours will break, and mine
Jeff> will work.

Gimme a break. Are you going to tell us that

	A * (B + 1) != A * B + A

for A != 1 ?? If you can't handle basic arithmetic, what makes you
think you can write a C program?

/Lars
--
Lars Fischer,  fischer@iesd.auc.dk   | Beauty is a French phonetic corruption
CS Dept., Univ. of Aalborg, DENMARK. |                   - FZ

volpe@camelback.crd.ge.com (Christopher R Volpe) (02/21/91)

In article <FISCHER.91Feb20184612@thiele.iesd.auc.dk>,
fischer@iesd.auc.dk (Lars P. Fischer) writes:
|>>>>>> dag@persoft.com (Daniel Glasser) writes:
|>
|>Daniel>Nit #2: You should simplify your expression in the "malloc()",
that is,
|>Daniel>		sizeof(char) * strlen(foo) + sizeof(char)
|>Daniel>	  could be written
|>Daniel>		sizeof(char) * (strlen(foo) + 1)
                                       ^
                                       |-This paren isn't closed, and
                                         may be causing much of the confusion.

|>
|>>>>>> jeff@onion.rain.com (Jeff Beadles) then said:
|>
|>Jeff> Untrue.  What if sizeof(char) != 1?  Yours will break, and mine
|>Jeff> will work.
|>
|>Gimme a break. Are you going to tell us that
|>
|>	A * (B + 1) != A * B + A
|>
|>for A != 1 ?? If you can't handle basic arithmetic, what makes you
|>think you can write a C program?

I think Lars and Jeff are talking about different expressions here, due to
the missing closing parenthesis. Jeff saw the expression
         sizeof(char) * strlen(foo) + 1 (he didn't see the '(' before 'strlen')
and noted that this wouldn't be equal to 
         sizeof(char) * strlen(foo) + sizeof(char)
in the event that sizeof(char) != 1. This is absolutely true, but a moot
point since sizeof(char) == 1 by definition. 

However, Lars saw the expression
         sizeof(char) * (strlen(foo) + 1) (he added the missing paren)
and noted that this is equal to
         sizeof(char) *  strlen(foo) + sizeof(char)
by mathematical identity (distribution of multiplication over addition)
regardless of whether or not sizeof(char) == 1.

The non-expression originally posted by Daniel, however, was not what
either of them saw, and they each extrapolated in different directions
to arrive at what they thought Daniel intended to write. I hope this
clears up the confusion.

-Chris                       
==================
Chris Volpe
G.E. Corporate R&D
volpecr@crd.ge.com

guido@cwi.nl (Guido van Rossum) (02/22/91)

jeff@onion.rain.com (Jeff Beadles) writes:

>Strcpy could also return an error, but I don't think that I've ever seen
>someone check for it. :-)

Actually, it is documented behaviour (at least on some systems) that
it returns NULL when the malloc fails.  I have written code that
assumes this.

--Guido (what a silly thread this is!)

vickde@vicstoy.UUCP (Vick De Giorgio) (02/22/91)

In article <1991Feb19.004526.16033@onion.rain.com> jeff@onion.rain.com (Jeff Beadles) writes:
>
>Untrue.  What if sizeof(char) != 1?  Yours will break, and mine will work.
> 
>{note:  I don't personally know of places where this isn't true, but then
>        again, some people think that sizeof (int) == sizeof (char *) :-}

sizeof(char) is by definition 1 -- K&R pg 188. Correct me if I'm wrong
(I'm sure someone will ;') but I don't think this has changed under ANSI.

=V=
-- 
Vick De Giorgio - vickde@vicstoy.UUCP -- I'd fly 10,000 miles to smoke a camel.
           UUCP - uunet!tarpit!bilver!vicstoy!vickde
                - The Philosopher's Stone Unix BBS, Orlando FL
                - (407) 299-3661   1200/2400   24 hours   8N1

rob@meaddata.com (Robert E. Lancia) (02/23/91)

>>>>> dag@persoft.com (Daniel Glasser) writes:

Daniel>Nit #2: You should simplify your expression in the "malloc()", that is,
Daniel>		sizeof(char) * strlen(foo) + sizeof(char)
Daniel>	  could be written
Daniel>		sizeof(char) * (strlen(foo) + 1)


>>>>> jeff@onion.rain.com (Jeff Beadles) then said:

Jeff> Untrue.  What if sizeof(char) != 1?  Yours will break, and mine
Jeff> will work.


>>>>> fischer@iesd.auc.dk (Lars P. Fischer) then writes:

Lars> Gimme a break. Are you going to tell us that
Lars> A * (B + 1) != A * B + A
Lars> for A != 1 ?? If you can't handle basic arithmetic, what makes you
Lars> think you can write a C program?


I think Lars might have jumped the gun a bit here.  Maybe, just MAYBE, Jeff
mis-read Daniel's rewrite as

    sizeof(char) * strlen(foo) + 1

instead of (the correct)

    sizeof(char) * (strlen(foo) + 1)

If this were the case, his comment makes perfect sense.  Regardless, I'm
giving Jeff the benefit of the doubt and blaming his eye doctor! :^)
--
|Robert Lancia                  |  I have a split   |  Mead Data Central
|(513) 297-2560                 |  personality, and |  Data Services Division
|rob@pmserv.meaddata.com        |  these are HIS    |  P.O. Box 308
|...!uunet!meaddata!pmserv!rob  |  comments.        |  Dayton, Ohio  45401