318

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

4

10 回答 10

392

听起来确实如此,假设您习惯于 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
}

换句话说:

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

  2. 如果分配失败,则立即设置errnoENOMEM返回NULL。设置errnotoENOMEMmallocPOSIX 中所做的,所以我们不需要在strdup. 如果您符合 POSIX,则 ISO C 实际上并没有强制要求存在,ENOMEM所以我没有在(b)中包含它。

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

请记住,这是概念上的定义。任何值得他们薪水的图书馆作者都可能提供了针对正在使用的特定处理器的高度优化的代码。


(a)但是,以str和小写字母开头的功能被标准保留用于未来的方向。来自C11 7.1.3 Reserved identifiers

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

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

str以、mem或和小写字母开头的函数名称wcs可以添加到<string.h>标头中的声明中。

因此,如果您想安全起见,您可能应该将其称为其他名称。


(b)更改基本上将替换if (d == NULL) return NULL;为:

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

(c)请注意,我使用strcpy它,因为这清楚地表明了意图。在某些实现中,使用 可能更快(因为您已经知道长度)memcpy,因为它们可能允许以更大的块或并行传输数据。或者它可能不会:-) 优化口头禅#1:“衡量,不要猜测”。

无论如何,如果您决定走那条路,您会执行以下操作:

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
}
于 2008-10-31T07:31:42.283 回答
88
char * strdup(const char * s)
{
  size_t len = 1+strlen(s);
  char *p = malloc(len);

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

也许代码比 with 快一点,strcpy()因为\0char 不需要再次搜索(它已经是 with strlen())。

于 2009-11-27T15:50:57.270 回答
53

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

于 2008-10-31T09:46:59.357 回答
18

来自strdup 人

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

于 2008-10-31T07:18:43.213 回答
4

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
}

所以,它所做的是给我们另一个字符串,它与它的参数给出的字符串相同,而不需要我们分配内存。但是我们仍然需要稍后释放它。

于 2013-06-27T09:51:02.733 回答
3

它通过运行传入的字符串的mallocstrcpy来复制传入的字符串。malloc 的缓冲区返回给调用者,因此需要在返回值上运行free 。

于 2008-10-31T07:22:27.637 回答
3

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

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

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

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

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

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

于 2014-12-17T12:00:42.937 回答
1

它所做的最有价值的事情是为您提供另一个与第一个相同的字符串,而无需您自己分配内存(位置和大小)。但是,如前所述,您仍然需要释放它(但这也不需要数量计算。)

于 2008-10-31T07:27:02.353 回答
1

该声明:

strcpy(ptr2, ptr1);

相当于(除了这会改变指针的事实):

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

然而:

ptr2 = strdup(ptr1);

相当于:

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

因此,如果您希望复制的字符串在另一个函数中使用(因为它是在堆部分创建的),您可以使用strdup,否则strcpy就足够了,

于 2015-12-03T09:04:04.863 回答
0

strdup() 函数是字符串复制的简写,它以字符串常量或字符串字面量的形式接收参数,并为字符串分配刚好足够的空间,并在分配的空间中写入相应的字符,最后返回分配的地址调用例程的空间。

于 2014-07-13T05:49:36.173 回答