strdup()
C中函数的目的是什么?
10 回答
听起来确实如此,假设您习惯于 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
}
换句话说:
它尝试分配足够的内存来保存旧字符串(加上一个'\0'字符来标记字符串的结尾)。
如果分配失败,则立即设置
errno
并ENOMEM
返回NULL
。设置errno
toENOMEM
是malloc
POSIX 中所做的,所以我们不需要在strdup
. 如果您不符合 POSIX,则 ISO C 实际上并没有强制要求存在,ENOMEM
所以我没有在(b)中包含它。否则分配工作,所以我们将旧字符串复制到新字符串(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
}
char * strdup(const char * s)
{
size_t len = 1+strlen(s);
char *p = malloc(len);
return p ? memcpy(p, s, len) : NULL;
}
也许代码比 with 快一点,strcpy()
因为\0
char 不需要再次搜索(它已经是 with strlen()
)。
没有必要重复其他答案,但请注意,strdup()
从 C 的角度来看,它可以做任何它想做的事情,因为它不是任何 C 标准的一部分。然而,它是由 POSIX.1-2001 定义的。
来自strdup 人:
该strdup()
函数应返回一个指向新字符串的指针,该字符串是 指向的字符串的副本s1
。返回的指针可以传递给free()
. 如果无法创建新字符串,则返回空指针。
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
}
所以,它所做的是给我们另一个字符串,它与它的参数给出的字符串相同,而不需要我们分配内存。但是我们仍然需要稍后释放它。
它通过运行传入的字符串的malloc和strcpy来复制传入的字符串。malloc 的缓冲区返回给调用者,因此需要在返回值上运行free 。
strdup
并strndup
在 POSIX 兼容系统中定义为:
char *strdup(const char *str);
char *strndup(const char *str, size_t len);
strdup()函数为 string 的副本分配足够的内存,进行复制并str
返回指向它的指针。
该指针随后可用作函数的参数free
。
如果可用内存不足,NULL
则返回并errno
设置为
ENOMEM
。
strndup()函数从字符串中复制最多len
字符,str
始终为空,以终止复制的字符串。
它所做的最有价值的事情是为您提供另一个与第一个相同的字符串,而无需您自己分配内存(位置和大小)。但是,如前所述,您仍然需要释放它(但这也不需要数量计算。)
该声明:
strcpy(ptr2, ptr1);
相当于(除了这会改变指针的事实):
while(*ptr2++ = *ptr1++);
然而:
ptr2 = strdup(ptr1);
相当于:
ptr2 = malloc(strlen(ptr1) + 1);
if (ptr2 != NULL) strcpy(ptr2, ptr1);
因此,如果您希望复制的字符串在另一个函数中使用(因为它是在堆部分创建的),您可以使用strdup
,否则strcpy
就足够了,
strdup() 函数是字符串复制的简写,它以字符串常量或字符串字面量的形式接收参数,并为字符串分配刚好足够的空间,并在分配的空间中写入相应的字符,最后返回分配的地址调用例程的空间。