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