strdup() - 它在C中做了什么?

Man*_*bts 296 c function strdup

strdup()C中函数的用途是什么?

pax*_*blo 360

究竟是什么样的,假设你已经习惯了C和UNIX分配单词的缩写方式,它会复制字符串 :-)

请记住,它实际上不是ISO C标准本身的一部分(a)(它是POSIX的东西),它实际上与以下代码一样:

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
}
Run Code Online (Sandbox Code Playgroud)

换一种说法:

  1. 它尝试分配足够的内存来保存旧字符串(加上'\ 0'字符来标记字符串的结尾).

  2. 如果分配失败,则设置errnoENOMEMNULL立即返回.在POSIX中设置errnoto ENOMEM是有效的malloc,所以我们不需要在我们的中明确地执行它strdup.如果你符合POSIX标准,那么ISO C实际上并没有强制要求存在,ENOMEM所以我没有把它包括在这里(b).

  3. 否则分配工作,所以我们将旧字符串复制到新字符串并返回新地址(调用者负责在某个时候释放).

请记住,这是概念性的定义.任何值得他们工资的图书馆作家都可能提供针对所使用的特定处理器的大量优化代码.


(a)但请注意,str标准为未来指示保留以小写字母开头的函数和小写字母.来自C11 7.1.3 Reserved identifiers:

每个标头声明或定义其关联子条款中列出的所有标识符,*可选地声明或定义其关联的未来库方向子条款中列出的标识符.**

未来的方向string.h可以在C11 7.31.13 String handling <string.h>:

str,memwcs小写字母开头的函数名称可以添加到<string.h>标题中的声明中.


(b)改变基本上将取代if (d == NULL) return NULL;:

if (d == NULL) {
    errno = ENOMEM;
    return NULL;
}
Run Code Online (Sandbox Code Playgroud)

  • 值得注意的是,正如Pax的示例实现暗示的那样,strdup(NULL)是未定义的,而不是您可以期望以任何可预测的方式运行的东西. (8认同)
  • @Alcot,`strdup`适用于那些需要为字符串副本分配堆内存的情况.否则你必须自己做.如果你已经_have_足够大的缓冲区(malloc'ed或其他),是的,使用`strcpy`. (5认同)
  • 另外,我认为malloc()会设置errno,所以你不必自己设置它.我认为. (2认同)
  • @acgtyrant:如果,按标准,你的意思是ISO标准(真正的C标准),不,它不是它的一部分.它是POSIX标准的一部分.然而,有很多C _implementations_提供它,尽管不是ISO C的官方部分.但是,即使他们没有,这个答案中的五线应该是绰绰有余的. (2认同)
  • 好的,@ chux,ISO只要求`{EDOM,EILSEQ,ERANGE}`作为必需的错误代码.已更新答案以解释此问题. (2认同)
  • @acgtyrant 截至 2019 年 6 月,“strdup”及其同级“strndup”已提交纳入即将推出的 ISO C23 标准。 (2认同)

Pat*_*ter 85

char * strdup(const char * s)
{
  size_t len = 1+strlen(s);
  char *p = malloc(len);

  return p ? memcpy(p, s, len) : NULL;
}
Run Code Online (Sandbox Code Playgroud)

也许代码比使用char 更快一些,strcpy()因为\0char不需要再次搜索(它已经存在strlen()).

  • @tristopia解除引用`NULL`不必崩溃; 这是未定义的.如果你想确定它崩溃了,写一个`emalloc`,在失败时调用`abort`. (3认同)

Chr*_*ung 51

没有必要重复其他答案,但请注意,strdup()从C角度来看,它可以做任何想做的事情,因为它不是任何C标准的一部分.但是它由POSIX.1-2001定义.

  • `strdup()`便携吗?不,在非POSIX环境中不可用(无论如何都可以实现).但是说POSIX功能可以做任何事情是非常迂腐的.POSIX是另一个*标准*,它与C一样好,甚至更受欢迎. (3认同)
  • @BlueMoon我认为重点是声称不符合POSIX的C实现仍然可以提供`strdup`函数作为扩展.在这样的实现中,不能保证`strdup`的行为与POSIX函数的行为相同.我不知道任何这样的实现,但合法的非恶意实现可能会出于历史原因提供`char*strdup(char*)`,并拒绝传递`const char*`的尝试. (2认同)

Von*_*onC 17

来自strdup man:

strdup()函数应返回一个指向新字符串的指针,该字符串是指向的字符串的副本s1.返回的指针可以传递给free().如果无法创建新字符串,则返回空指针.


小智 5

strdup() 对包含结束符 '\0' 的字符数组进行动态内存分配,并返回堆内存的地址:

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
}
Run Code Online (Sandbox Code Playgroud)

因此,它的作用是为我们提供另一个与其参数给出的字符串相同的字符串,而不需要我们分配内存。但稍后我们仍然需要释放它。


Suj*_*mar 5

strdupstrndup在 POSIX 兼容系统中定义为:

char *strdup(const char *str);
char *strndup(const char *str, size_t len);
Run Code Online (Sandbox Code Playgroud)

strdup ()函数为字符串的副本分配足够的内存str,进行复制,并返回指向它的指针。

该指针随后可以用作函数的参数free

如果可用内存不足,NULL则返回并errno设置为 ENOMEM

strndup ()len函数从字符串中复制最多字符str,始终以 null 终止复制的字符串。