strdup() - what does it do in C?
Asked Answered
P

11

336

What is the purpose of the strdup() function in C?

Picco answered 31/10, 2008 at 7:15 Comment(6)
there is also strdupa() (in the GNU C library), a nice function that is similar to strdup(), but allocates memory on the stack. Your program don't need to free the memory explicitly as in case with strdup(), it will be freed automatically when you exit the function where strdupa() was calledNorth
strdupa is dangerous and should not be used unless you've already determined that strlen is very small. But then you could just use a fixed-size array on the stack.Chordate
@slacker google translate isn't being helpful... What does strdup/strdupa mean in Polish?Windrow
@Windrow hereSelfcontent
Here is the difference between strdup and strcpy https://mcmap.net/q/100501/-strcpy-vs-strdupBaugher
Just came here to add that both "dupa" and "string" have something to do with ass in Polish.Hypertension
J
408

Exactly what it sounds like, assuming you're used to the abbreviated way in which C and UNIX assigns words, it duplicates strings :-)

Keeping in mind it's actually not part of the current (C17) ISO C standard itself(a) (it's a POSIX thing), it's effectively doing the same as the following code:

char *strdup(const char *src) {
    char *dst = malloc(strlen (src) + 1);  // Space for length plus nul
    if (dst == NULL) return NULL;          // No memory
    strcpy(dst, src);                      // Copy the characters
    return dst;                            // Return the new string
}

In other words:

  1. It tries to allocate enough memory to hold the old string (plus a '\0' character to mark the end of the string).

  2. If the allocation failed, it sets errno to ENOMEM and returns NULL immediately. Setting of errno to ENOMEM is something malloc does in POSIX so we don't need to explicitly do it in our strdup. If you're not POSIX compliant, ISO C doesn't actually mandate the existence of ENOMEM so I haven't included that here(b).

  3. Otherwise the allocation worked so we copy the old string to the new string(c) and return the new address (which the caller is responsible for freeing at some point).

Keep in mind that's the conceptual definition. Any library writer worth their salary may have provided heavily optimised code targeting the particular processor being used.

One other thing to keep in mind, it looks like this is currently slated to be in the C2x iteration of the standard, along with strndup, as per draft N2912 of the document.


(a) However, functions starting with str and a lower case letter are reserved by the standard for future directions. From C11 7.1.3 Reserved identifiers:

Each header declares or defines all identifiers listed in its associated sub-clause, and optionally declares or defines identifiers listed in its associated future library directions sub-clause.*

The future directions for string.h can be found in C11 7.31.13 String handling <string.h>:

Function names that begin with str, mem, or wcs and a lowercase letter may be added to the declarations in the <string.h> header.

So you should probably call it something else if you want to be safe.


(b) The change would basically be replacing if (d == NULL) return NULL; with:

if (d == NULL) {
    errno = ENOMEM;
    return NULL;
}

(c) Note that I use strcpy for that since that clearly shows the intent. In some implementations, it may be faster (since you already know the length) to use memcpy, as they may allow for transferring the data in larger chunks, or in parallel. Or it may not :-) Optimisation mantra #1: "measure, don't guess".

In any case, should you decide to go that route, you would do something like:

char *strdup(const char *src) {
    size_t len = strlen(src) + 1;       // String plus '\0'
    char *dst = malloc(len);            // Allocate space
    if (dst == NULL) return NULL;       // No memory
    memcpy (dst, src, len);             // Copy the block
    return dst;                         // Return the new string
}
Jequirity answered 31/10, 2008 at 7:15 Comment(17)
It is worth noting, that as Pax' sample implementation implies, strdup(NULL) is undefined and not something you can expect to behave in any predicable way.Utopia
Also, I think malloc() would set errno, so you shouldn't have to set it yourself. I think.Lundgren
That's a good point, @Chris. I changed it because I had a need to look at the man page for strdup() and noticed I'd left that out. But I forgot that malloc() did that for it. So I'll revert the code.Jequirity
With the existence of strcpy, what's the point of strdup? Safer for string copy?Wonderland
@Alcot, strdup is for those situations where you want heap memory allocated for the string copy. Otherwise you have to do it yourself. If you already have a big enough buffer (malloc'ed or otherwise), yes, use strcpy.Jequirity
It would be nice to have an example of how to use itGwenny
Is there any standard or C implemetation support this function now? Thank you!Soapsuds
@acgtyrant: if, by standard, you mean the ISO standard (the real C standard), no, it's not part of it. It is part of the POSIX standard. However, there are plenty of C implementations that provide it, despite not being an official part of ISO C. However, even if they didn't, the five-liner in this answer should be more than sufficient.Jequirity
Well, I feel like an idiot. "Exactly what it sounds like" -> kept saying to myself "str-d-up" thinking it was a casing method.Preoccupy
@Jequirity IIRC, "If the allocation failed, it sets errno to ENOMEM" is a POSIX spec - not a C one. If code needs to create strdup(), likely not on a POSIX system, might not malloc() also not set errno? So to provide POSIX like functionality, perhaps this strdup() should also set errno as needed. Otherwise calling code should not count on errno to ENOMEM on failure via this strdup()Markland
Good point, @chux, ISO mandates only { EDOM, EILSEQ, ERANGE } as required error codes. Have updated the answer to account for this.Jequirity
@Jequirity as people do not often read the other answers, please change this to use memcpy instead as the "canonical strdup implementation" ;)Karame
@Antti, I'm not sure why you would think that the memcpy variant would be canonical. It's possible it may be faster but I prefer to optimise for readability first :-)Jequirity
No, this question :D for those asking to port strdup. BTW, funny thing, GCC does optimize this to memcpy but clang misses it.Karame
@AnttiHaapala, have added a footnote to that effect.Jequirity
@Soapsuds As of 6/2019, strdup and its sibling strndup have been submitted for inclusion in the upcoming ISO C23 standard.Dhruv
Good find, @TomLint, updated the answer to note this.Jequirity
F
90
char * strdup(const char * s)
{
  size_t len = 1+strlen(s);
  char *p = malloc(len);

  return p ? memcpy(p, s, len) : (errno = ENOMEM, NULL);
}

Maybe the code is a bit faster than with strcpy() as the \0 char doesn't need to be searched again (It already was with strlen()).

EDIT: according to some documents, strdup() sets errno to ENOMEM when allocation fails.

Foley answered 27/11, 2009 at 15:50 Comment(4)
Thanks. In my personal implementation I make it even "worse". return memcpy(malloc(len), s, len); as I prefer the crash on allocation rather than the NULL on allocation failure.Wiggins
@tristopia dereferencing NULL doesn't have to crash; it's undefined. If you want to be sure it crashes, write an emalloc which calls abort upon fail.Goulette
I know that, but my implementation is guaranteed to run only on Solaris or Linux (by the very nature of the app).Wiggins
@tristopia: It's good to be in the habit of doing things the best way. Get in the habit of using emalloc even if it's not necessary on Solaris or Linux so that you'll be using it in the future when you write code on other platforms.Tirza
L
53

No point repeating the other answers, but please note that strdup() can do anything it wants from a C perspective, since it is not part of any C standard. It is however defined by POSIX.1-2001.

Lareine answered 31/10, 2008 at 9:46 Comment(4)
Is strdup() portable? No, not available in non-POSIX environment (trivially implementable anyway). But to say a POSIX function can do anything is quite pedantic. POSIX is another standard that's as good as C's and even more popular.Antonina
@BlueMoon I think the point is that a C implementation that claims no conformance to POSIX may still provide a strdup function as an extension. On such an implementation, there's no guarantee that that strdup behaves the same way as the POSIX function. I don't know of any such implementations, but a legitimate non-malicious implementation might provide char *strdup(char *) for historic reasons, and reject attempts to pass in a const char *.Revivalism
What is the difference between C standard and POSIX ? By C standard you mean, it does not exist in C standard libraries?Terr
@KorayTugay They are different standards. Better to treat them as unrelated unless you know that the standard for a particular C function conforms to the POSIX standard, and that your compiler/library conforms to the standard for that function.Kiel
S
18

From strdup man:

The strdup() function shall return a pointer to a new string, which is a duplicate of the string pointed to by s1. The returned pointer can be passed to free(). A null pointer is returned if the new string cannot be created.

Shelter answered 31/10, 2008 at 7:18 Comment(0)
O
5

strdup() does dynamic memory allocation for the character array including the end character '\0' and returns the address of the heap memory:

char *strdup (const char *s)
{
    char *p = malloc (strlen (s) + 1);   // allocate memory
    if (p != NULL)
        strcpy (p,s);                    // copy string
    return p;                            // return the memory
}

So, what it does is give us another string identical to the string given by its argument, without requiring us to allocate memory. But we still need to free it, later.

Outwards answered 27/6, 2013 at 9:51 Comment(0)
A
5

strdup and strndup are defined in POSIX compliant systems as:

char *strdup(const char *str);
char *strndup(const char *str, size_t len);

The strdup() function allocates sufficient memory for a copy of the string str, does the copy, and returns a pointer to it.

The pointer may subsequently be used as an argument to the function free.

If insufficient memory is available, NULL is returned and errno is set to ENOMEM.

The strndup() function copies at most len characters from the string str always null terminating the copied string.

Amelia answered 17/12, 2014 at 12:0 Comment(0)
C
3

It makes a duplicate copy of the string passed in by running a malloc and strcpy of the string passed in. The malloc'ed buffer is returned to the caller, hence the need to run free on the return value.

Cystocele answered 31/10, 2008 at 7:22 Comment(0)
B
2

The statement:

strcpy(ptr2, ptr1);

is equivalent to (other than the fact this changes the pointers):

while(*ptr2++ = *ptr1++);

Whereas:

ptr2 = strdup(ptr1);

is equivalent to:

ptr2 = malloc(strlen(ptr1) + 1);
if (ptr2 != NULL) strcpy(ptr2, ptr1);

So, if you want the string which you have copied to be used in another function (as it is created in heap section), you can use strdup, else strcpy is enough,

Browne answered 3/12, 2015 at 9:4 Comment(0)
T
1

The most valuable thing it does is give you another string identical to the first, without requiring you to allocate memory (location and size) yourself. But, as noted, you still need to free it (but which doesn't require a quantity calculation, either.)

Tarsia answered 31/10, 2008 at 7:27 Comment(0)
C
0

The strdup() function is a shorthand for string duplicate, it takes in a parameter as a string constant or a string literal and allocates just enough space for the string and writes the corresponding characters in the space allocated and finally returns the address of the allocated space to the calling routine.

Catamenia answered 13/7, 2014 at 5:49 Comment(1)
The argument to strdup does not need to be a string constant, it must be a C string, ie a null terminated array of char.Stratocumulus
P
0

Using strdup you can get a modifiable copy of the string word or any string. In this way, you can change its contents without encountering the problems of replacing the hard memory.

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

int main() {
    const char* original = "Hello, World!";
    char *copy = strdup(original); // Create a copy

    if (copy != NULL) {
        // Modify the copy
        strcpy(copy, " Again Hello World \n");

        printf("Original: %s\n", original); 
        printf("Copy: %s\n", copy);         

        free(copy); 
    } else {
        printf("Memory allocation failed.\n");
    }

    return 0;
}
Panlogism answered 28/8, 2023 at 12:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.