6

Can I use malloc and strcpy to replace it? Which one is better?

e.g.:

char *s = "Global View";
char *d;
d = strdup(s);
free(d);

or

char *s = "Global View";
char *d = malloc(strlen(s) +1);
strcpy(d,s);
free(d);
BaseZen
  • 8,650
  • 3
  • 35
  • 47
Jarry
  • 81
  • 1
  • 4
  • 5
    strdup likely avoids the need to find the length of the string twice and it's more descriptive when I see it in code. Really opinion based though. – Retired Ninja Sep 26 '16 at 03:20
  • No much difference when you're using pure C, but there are some frameworks which have redefined strdup indeed, e.g. PHP Zend – Frederick Zhang Sep 26 '16 at 03:22
  • 6
    `strdup` is not part of ISO C – M.M Sep 26 '16 at 03:26
  • @RetiredNinja tell us how `strdp` behave differently than `strlen`+`strcpy` (or `memcpy`) ? – Jean-Baptiste Yunès Sep 26 '16 at 05:06
  • 3
    You should avoid `strdup` when writing portable code. It is trivial to implement it yourself and there is no reason to suspect that the library implementation will be much more efficient, since the optimizations lie in `strlen` and `memcpy`. – Lundin Sep 26 '16 at 07:52
  • 2
    @M.M, `strdup` has been [POSIX for at least 12 years](http://pubs.opengroup.org/onlinepubs/009695399/functions/strdup.html). – Andrew Henle Sep 26 '16 at 11:16
  • @Lundin - It is not better to avoid strdup() if you want to increase portability, just provide a portable implementation of it. By writing strdup() you can leverage libc when available, and the meaning and use of the code is much clearer. – clearlight Sep 26 '16 at 16:48
  • @nerdistcolony In which case you might as well provide a custom string class that handles all such things internally. – Lundin Sep 27 '16 at 06:12
  • @Lundin Agree. "provide a custom string" --> A rite of passage for many a C programmer. Trouble is, even with a fantastic yet-another-string functions set and `typedef/struct`, code still needs to interface with that ubiquitous pesky _C string_ sometimes. – chux - Reinstate Monica Jan 16 '17 at 19:24

4 Answers4

9

Which one is better?

strdup(s); itself does not create a problem when allocation failures (calling code still needs to handle a NULL return), unlike the below which is undefined behavior or UB.

char *d = malloc(strlen(s) +1);
strcpy(d,s); // should not be called if `d == NULL`.

A typical implementation of strdup(s) does not walk the length of s twice like the alternate might.

// 1st pass to find length of `s`
char *d = malloc(strlen(s) +1);
// Weak compiler/library may run 2nd pass to find length of `s` and then copy
strcpy(d,s);

A good strdup(s) will make one pass and use optimal copy code when the length warrants it. Perhaps by using memcpy() or equivalent.

The key is that strdup() is expected to be used often and a library that implements this non-standard C library function is expected to be crafted to perform optimally. Use the best tool when it is available. Sample implementation:

#include <errno.h>
#include <stdlib.h>

char *my_strdup(const char *s) {
  if (s == NULL) { // Optional test, s should point to a string
    #ifdef EINVAL
      errno = EINVAL;  // For systems that support this "invalid argument" errno
    #endif
    return NULL;  
  }
  size_t siz = strlen(s) + 1;
  char *y = malloc(siz);
  if (y != NULL) {
    memcpy(y, s, siz);
  } else {
    #ifdef ENOMEM
      errno = ENOMEM;  // For systems that support this "out-of-memory" errno
    #else
      ;
    #endif
  }
  return y;
}

Rolling your own strdup() does collide with reserved name space @Jonathan Leffler @Joshua

An important advantage to malloc()/memcpy()/strcpy() is that they are standard C library functions. strdup() is not in the standard C library, although it is very commonly implemented.

[edit] strdup() maybe in C2x: Add strdup and strndup to C2X?

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • 1
    In fact the standard goes so far to say the name is reserved for this function. This has the effect that a library should not reuse the name to mean something else. – Joshua Sep 26 '16 at 03:47
  • What "make one pass" really means here ? One pass for the length, one pass for the copy ? Isn't it mandatory ? – Jean-Baptiste Yunès Sep 26 '16 at 05:08
  • 2
    The standard doesn't mention `strdup()` per se. It just defines future library directions in §7.31.13 String handling `` _Function names that begin with `str`, `mem`, or `wcs` and a lowercase letter may be added to the declarations in the `` header._ — a blanket prescription which certainly includes `strdup()` but doesn't single it out from all the other function names that match the pattern `str[a-z].*`. – Jonathan Leffler Sep 26 '16 at 05:13
  • @Jean-Baptiste Yunès One pass referring to how many times the string length needs to be determined. Optimized compilers may analyze the code and "know" `strcpy()` may be substituted with faster code than the usual `strcpy()`. As the previous `strlen()` has determined the length, something like `memcpy(dest, src, length+1)` may occur. `memcpy()` like code often takes advantage of knowing the length _a priori_ to perform faster copies. True that this is a second pass, but it may be a significant faster pass than `strcpy()`. YMMV. – chux - Reinstate Monica Sep 26 '16 at 14:25
  • @Jean-Baptiste Yunès Of course this is very implementation dependent and is a micro optimization (micro-op). OTOH, give that _lots_ of CPU time may be spent in string copying, details like this are worthy of micro-op from time to time. I prefer to use `strdup()` and move on to other issues. – chux - Reinstate Monica Sep 26 '16 at 14:25
  • “`strdup(s);` does not create a problem when allocation [fails] …” I don’t agree. The caller still has to check whether it got a valid copy or got `NULL`, after all. Most code would care about the difference, yes? – Tom Zych Jan 16 '17 at 18:57
  • @TomZych The issue is that `strdup()`, itself, does not cause undefined behavior when memory allocation fails. `d = strdup(s); free(d);` is fine - with or without an out-of-memory. A check was not needed in this trivial example. OP's code `char *d = malloc(strlen(s) +1); strcpy(d,s);` is UB when allocation fails. How following code uses the return value of `strdup()` is important, as you commented. Robust code typically should check its returned value. – chux - Reinstate Monica Jan 16 '17 at 19:14
  • *`strdup()` is not in the standard C library* [`strdup()` is POSIX](https://pubs.opengroup.org/onlinepubs/9699919799/functions/strdup.html), so it's actually quite widely available, especially considering [Microsoft implements 'strdup()` on Windows](https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/strdup-wcsdup?view=vs-2019). – Andrew Henle Feb 20 '20 at 16:07
  • @AndrewHenle True about POSIX and VC (not "Windows" as it is a compiler thing, not an OS one) and availability. It remains, are they functionally the _same_? Maybe, maybe not Corner case include value of `errno` on failure. POSIX is well defined. Uncertain about VC. Will `errno` state become an implementation defined behavior should `strdup()` enter C STL? – chux - Reinstate Monica Feb 20 '20 at 17:44
  • Is there any major platform today that _doesn’t_ have `strdup()` and `strndup()` available as part of the system library? – Dúthomhas Dec 28 '22 at 21:48
  • Dúthomhas, Yes any library with strict C adherence does not have `strdup()`. Interesting question for you to post on SO. I would also not be surprised to not find `strdup()` at all on embedded compilers. – chux - Reinstate Monica Dec 28 '22 at 21:50
1

There is not much difference other than strdup is shorted. strdup == malloc + strcpy

JamesWebbTelescopeAlien
  • 3,547
  • 2
  • 30
  • 51
  • 3
    In the case of doing it manually, the result from `malloc` should really be checked before calling `strcpy`. In the case of using the `strdup` version, the final result should be checked for NULL. – BaseZen Sep 26 '16 at 03:21
1

Use strdup() to be consistent in your use of libc string handling functions. strdup() implies the operand is libc's model of a null-terminated string.

libc's str...() functions flawlessly address the basics of C string handling, so use them whenever they'll suffice, if for no other reason than to make your code quicker to understand by others, and to avoid writing more code than necessary.

I personally wouldn't mix models without a compelling reason. Situations may arise where it is helpful or necessary to supplement libc string functions with custom functions, or maybe bypass them entirely, for example, not all C platforms provide libc. Maybe there are linking issues, or your working in a kernel context and can't access libc without crashing or a lot of effort, etc...

It can be tempting by using 0 or NULL to indicate the literal value '\0'. Most C programmers know all forms of NULL will work. The advantage of using '\0' where it's relevant is that it is a succinct way to disambiguate your intention. '\0' represents a character and nothing else.

clearlight
  • 12,255
  • 11
  • 57
  • 75
0

I would suggest to use strdup() ever. And malloc() + memcpy() only with big sized strings, where you know the actual size. This allow you to save the time to score the string to get the lenght. Since this is a very fast function, you can appreciate the difference only up several megabytes text. Let suppose you have a struct string

 typedef struct string
 {
    char* st;
    long buf;
    long n;
 } String;

In this case you have ever available the actual size of the string, so if I should strdup() this string I would write:

 char * stringdup(String *st)
{
    char *res=malloc(st->n);
    res?memcpy(res,st->st,st->n):NULL;
} 

You can notice something: when I duplicate the string, I return a char * and not a String. Experience says that the struct string, is nice to use just to build strings, but is not comfortable to use to store strings. Because all debugger can show a char* as string, but nobody is going to know your struct. So once you define your final string, better leave from the struct. You save space, and the debug get faster. This is also the reason that explane because for small text, doesn't worth use such instructions. You are never going to appreciate it but it mess your code.

UPDATE:

I forgot another situation. You can use malloc() + memcpy() when you have to copy just a subset of your string. strdup() and strcpy() are going to copy everything. But if you want just a part of your text, you should use these instructions.

Community
  • 1
  • 1
jurhas
  • 613
  • 1
  • 4
  • 12
  • 1
    Concerning `memcpy(res,st->st,1)` Why copy only 1 character into `res`? Unclear why code uses type `long` for a string's size. Suggest `size_t` instead. – chux - Reinstate Monica Sep 26 '16 at 14:30
  • @chux, yeah! `*res = *(st->st)` - Faster code - no library call. – clearlight Sep 26 '16 at 23:46
  • yeap you are right. I correct it. Another case where you use this form is also when you have to concatenate a lot of strings. So the effort to use a struct string, is justified only with intensive use of it. @nerdist colony: this copy only the first charachter. – jurhas Sep 27 '16 at 07:19