Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

strdup() - what does it do in C?

Tags:

c

function

strdup

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

like image 895
Manoj Doubts Avatar asked Oct 31 '08 07:10

Manoj Doubts


People also ask

Why do we use strdup?

Writing to a constant string will produce unexpected results and often crashes. The strdup function fixes the problem because it creates a mutable copy which is placed into a slot expecting a mutable string.

What does strdup return?

The strdup() function returns a pointer to a new string which is a duplicate of the string s. Memory for the new string is obtained with malloc(3), and can be freed with free(3). The strndup() function is similar, but copies at most n bytes.

Does strdup allocate memory?

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

What can I use instead of strdup in C?

syntax: char *strndup(const char *s, size_t n); This function is similar to strdup(), but copies at most n bytes. Note: If s is longer than n, then only n bytes are copied, and a NULL ('\0') is added at the end.


3 Answers

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
}
like image 109
17 revs, 2 users 99% Avatar answered Oct 07 '22 22:10

17 revs, 2 users 99%


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()).

like image 22
Patrick Schlüter Avatar answered Oct 07 '22 21:10

Patrick Schlüter


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.

like image 42
Chris Young Avatar answered Oct 07 '22 22:10

Chris Young