strdup()
C函数的目的是什么?
strdupa
是危险的,除非已确定strlen
很小,否则不应该使用。但是,您可以仅在堆栈上使用固定大小的数组。
strdup
/ strdupa
平均在波兰?
strdup()
C函数的目的是什么?
strdupa
是危险的,除非已确定strlen
很小,否则不应该使用。但是,您可以仅在堆栈上使用固定大小的数组。
strdup
/ strdupa
平均在波兰?
Answers:
听起来确实如此,假设您已经习惯了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
立即返回。在POSIX中,设置为errno
to ENOMEM
是malloc
必需的,因此我们不需要在中显式地进行设置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
}
strdup
用于需要为字符串副本分配堆内存的情况。否则,您必须自己做。如果您已经有足够大的缓冲区(已分配内存或以其他方式分配),请使用strcpy
。
{ EDOM, EILSEQ, ERANGE }
作为必需的错误代码。为此已更新了答案。
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(它已经与在一起strlen()
)。
return memcpy(malloc(len), s, len);
因为我更喜欢NULL
分配失败而不是 分配失败。
NULL
不必崩溃;它是未定义的。如果要确保它崩溃,请编写一个失败时emalloc
调用abort
。
emalloc
即使没有在Solaris或Linux上使用它,也要养成使用的习惯,以便将来在其他平台上编写代码时使用它。
没有必要重复其他答案,但是请注意strdup()
,由于它不是任何C标准的一部分,因此可以从C角度执行任何所需的操作。但是,它是由POSIX.1-2001定义的。
strdup()
便携式?否,在非POSIX环境中不可用(无论如何还是可以实现)。但是说一个POSIX函数可以做任何事情都是很古怪的。POSIX是另一个标准这是好为C的,甚至更受欢迎。
strdup
扩展功能。在这种实现方式上,不能保证其strdup
行为与POSIX函数相同。我不知道有任何这样的实现,但是char *strdup(char *)
出于历史原因,合法的非恶意实现可能会提供,并拒绝传递的尝试const char *
。
来自strdup man:
该strdup()
函数应返回一个指向新字符串的指针,该字符串与所指向的字符串的副本相同s1
。返回的指针可以传递给free()
。如果无法创建新字符串,则返回空指针。
strdup
并且strndup
在符合POSIX的系统中定义为:
char *strdup(const char *str);
char *strndup(const char *str, size_t len);
所述的strdup()函数分配用于字符串的副本足够的存储器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
就足够了,