330

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

Grijesh Chauhan
  • 57,103
  • 20
  • 141
  • 208
Manoj Doubts
  • 13,579
  • 15
  • 42
  • 45
  • 46
    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 called – dmityugov Oct 31 '08 at 13:05
  • 11
    `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. – R.. GitHub STOP HELPING ICE Dec 29 '10 at 16:34
  • 4
    @slacker google translate isn't being helpful... What does `strdup`/`strdupa` mean in Polish? – haneefmubarak Mar 07 '15 at 16:47
  • 17
    @haneefmubarak [here](https://translate.google.co.il/?ie=UTF-8&hl=en&client=tw-ob#pl/en/dupa) – anatolyg Sep 30 '15 at 17:02
  • Here is the difference between strdup and strcpy https://stackoverflow.com/questions/14020380/strcpy-vs-strdup – Siva Prakash Aug 21 '18 at 08:31
  • 1
    Just came here to add that both "dupa" and "string" have something to do with ass in Polish. – Big Temp May 11 '20 at 20:02

11 Answers11

404

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
}
paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • 8
    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. – unwind May 22 '09 at 10:14
  • 2
    Also, I think malloc() would set errno, so you shouldn't have to set it yourself. I think. – Chris Lutz Jun 08 '09 at 03:58
  • 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. – paxdiablo Jun 08 '09 at 04:09
  • 1
    With the existence of `strcpy`, what's the point of `strdup`? Safer for string copy? – Alcott Feb 28 '12 at 00:51
  • 5
    @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`. – paxdiablo Feb 28 '12 at 01:15
  • It would be nice to have an example of how to use it – puk Nov 06 '13 at 18:13
  • Is there any standard or C implemetation support this function now? Thank you! – acgtyrant Apr 16 '14 at 07:44
  • 2
    @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. – paxdiablo Apr 16 '14 at 10:37
  • Well, I feel like an idiot. "Exactly what it sounds like" -> kept saying to myself "str-d-up" thinking it was a casing method. – jdknight Sep 18 '14 at 15:18
  • @paxdiablo 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()` – chux - Reinstate Monica Jan 30 '18 at 04:29
  • 2
    Good point, @chux, ISO mandates only `{ EDOM, EILSEQ, ERANGE }` as required error codes. Have updated the answer to account for this. – paxdiablo Jan 30 '18 at 06:13
  • @paxdiablo as people do not often read the other answers, please change this to use `memcpy` instead as the "canonical strdup implementation" ;) – Antti Haapala -- Слава Україні Apr 22 '19 at 11:28
  • @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 :-) – paxdiablo Apr 22 '19 at 22:16
  • No, *this* question :D for those asking to port strdup. BTW, funny thing, GCC does optimize this to memcpy but clang misses it. – Antti Haapala -- Слава Україні Apr 22 '19 at 22:19
  • @AnttiHaapala, have added a footnote to that effect. – paxdiablo Apr 23 '19 at 01:36
  • 2
    @acgtyrant As of 6/2019, `strdup` and its sibling `strndup` have been submitted for inclusion in the upcoming ISO C23 standard. – Tom Lint Jun 07 '22 at 14:21
  • Good find, @TomLint, updated the answer to note this. – paxdiablo Jun 08 '22 at 03:53
90
char * strdup(const char * s)
{
  size_t len = 1+strlen(s);
  char *p = malloc(len);

  return p ? memcpy(p, s, len) : 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()).

Patrick Schlüter
  • 11,394
  • 1
  • 43
  • 48
  • 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. – Patrick Schlüter Dec 30 '10 at 21:00
  • 5
    @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. – Dave Dec 30 '11 at 03:28
  • I know that, but my implementation is guaranteed to run only on Solaris or Linux (by the very nature of the app). – Patrick Schlüter Dec 30 '11 at 13:01
  • 1
    @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. – ArtOfWarfare Feb 28 '15 at 20:20
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.

jotik
  • 17,044
  • 13
  • 58
  • 123
Chris Young
  • 15,627
  • 7
  • 36
  • 42
  • 7
    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. – P.P May 09 '14 at 08:58
  • 2
    @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 *`. –  Mar 06 '15 at 22:19
  • What is the difference between C standard and POSIX ? By C standard you mean, it does not exist in C standard libraries? – Koray Tugay Mar 22 '15 at 11:35
  • @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. – Matthew Read Mar 23 '15 at 19:40
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.

Grijesh Chauhan
  • 57,103
  • 20
  • 141
  • 208
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
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.

Zaffy
  • 16,801
  • 8
  • 50
  • 77
Karshit
  • 51
  • 1
  • 1
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.

chqrlie
  • 131,814
  • 10
  • 121
  • 189
Sujay Kumar
  • 520
  • 8
  • 19
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.

jussij
  • 10,370
  • 1
  • 33
  • 49
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,

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
Md. Al Amin Bhuiyan
  • 303
  • 1
  • 3
  • 12
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.)

dkretz
  • 37,399
  • 13
  • 80
  • 138
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.

AnkitSablok
  • 3,021
  • 7
  • 35
  • 52
  • 2
    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`. – chqrlie Aug 18 '18 at 11:03
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;
}
Paroz
  • 39
  • 4