在C中,strdup()函数的用途是什么?
- 因此,有strdupa()(GNU C库函数),这是类似于一个很好的strdup(),但在allocates内存堆栈。你的程序不需要显式的无记忆的案例与strdup(AS),它会自动释放,当你退出该函数被称为strdupa(where)
- dmityugov strdupa()@:+ 1)。这是特别有趣的功能使用:如果你说波兰)。
- 这是hilarious!
- strdupa是危险的和不应该是已经确定的,除非你使用的是strlen是非常小的。然后你只是使用一个固定大小的阵列上的堆栈。
- 谷歌翻译:懒鬼是不是人……什么是strdup/ strdupa均值在波兰?
- 在"haneefmubarak
- 这是在strdup和strcpy stackoverflow.com /问题/ / 14020380 vs strdup strcpy
这听起来很像,假设您习惯了C和Unix分配单词的缩写方式,它会复制字符串:—)
记住,它实际上不是ISO C标准本身的一部分(A)(这是一个POSIX的东西),它实际上与下面的代码一样:
1 2 3 4 5 6
| 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
} |
换句话说:
它试图分配足够的内存来保存旧字符串(加上一个' '字符来标记字符串的结尾)。
如果分配失败,则将errno设置为ENOMEM,并立即返回NULL。将errno设置为ENOMEM是malloc在posix中所做的,因此我们不需要在strdup中显式地进行设置。如果您不符合POSIX,ISO C实际上并不要求存在ENOMEM,所以我在这里没有包括(b)。
否则,分配会起作用,因此我们将旧字符串复制到新字符串(C)并返回新地址(调用者在某个时刻负责释放新地址)。
记住这是概念上的定义。任何一个有价值的图书馆作者都可能提供针对所使用的特定处理器的高度优化的代码。
(a)但是,标准保留了以str和小写字母开头的功能,以供将来使用。来自C11 7.1.3 Reserved identifiers:
Each header declares or defines all identifiers listed in its associated sub-clause, and *optionally declares or defines identifiers listed in its associated future library directions sub-clause.**
号
string.h的未来方向可在C11 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.
号
所以,如果你想安全的话,你应该把它叫做别的东西。
(b)这一变化基本上将取代if (d == NULL) return NULL;,即:
1 2 3 4
| if (d == NULL) {
errno = ENOMEM;
return NULL;
} |
号
(c)注意,我使用strcpy来表示这一点,因为这清楚地表明了我的意图。在某些实现中,使用memcpy可能更快(因为您已经知道长度),因为它们可能允许以更大的块或并行方式传输数据。或者它可能不会:(-)优化咒语1:"测量,不要猜测"。
在任何情况下,如果你决定走这条路,你会做如下的事情:
1 2 3 4 5 6 7
| 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
} |
- 值得注意的是,正如pax的示例实现所暗示的那样,strdup(空)是未定义的,您不能期望它以任何可预测的方式运行。
- 另外,我认为malloc()会设置errno,所以您不必自己设置它。我想。
- 这是一个很好的观点,@克里斯。我更改了它,因为我需要查看strdup()的手册页,并注意到我忽略了这一点。但我忘了Malloc()是为它做的。所以我将恢复代码。
- 你不应该把malloc()的结果……
- 随着strcpy的存在,strdup有什么意义?字符串复制更安全?
- @alcot,strdup用于那些需要为字符串复制分配堆内存的情况。否则你必须自己做。如果已经有足够大的缓冲区(malloc'ed或其他),可以,使用strcpy。
- 最好有一个如何使用它的例子
- 现在是否有任何标准或C实现支持此功能?谢谢您!
- @Acgtyrant:如果按标准来说,你指的是ISO标准(真正的C标准),不,它不是它的一部分。它是POSIX标准的一部分。然而,有很多C实现提供了它,尽管它不是ISO C的正式部分。但是,即使它们没有,这个答案中的五行代码也应该足够了。
- 嗯,我觉得自己像个白痴。"听上去正是这样——>一直对自己说"str-d-up",认为这是一种套管方法。
- @paxdiablo iirc,"如果分配失败,它将errno设置为ENOMEM"是posix规范,而不是c规范。如果代码需要创建strdup(),可能不是在posix系统上,那么malloc()是否也不设置errno?因此,为了提供类似posix的功能,可能这个strdup()还应该根据需要设置errno。否则,如果通过该strdup()失败,则调用代码不应计为errno到ENOMEM。
- 很好,@chux,iso只要求{ EDOM, EILSEQ, ERANGE }作为所需的错误代码。已将此问题的答案更新为帐户。
- 非常清楚的定义+1票。
- @paxdiablo由于人们不经常阅读其他答案,请将其更改为使用memcpy而不是"规范strdup实现";)
- @安蒂,我不知道你为什么会认为memcpy变体是规范的。它可能更快,但我更喜欢先优化可读性:—)
- 不,这个问题:对于那些要求端口strdup的人。顺便说一句,有意思的是,GCC确实将此优化为memcpy,但Clang错过了。
- @安提哈帕拉,增加了一个脚注的效果。
1 2 3 4 5 6 7
| char * strdup (const char * s )
{
size_t len = 1+strlen(s );
char *p = malloc(len );
return p ? memcpy(p , s , len ) : NULL ;
} |
。
可能代码比strcpy()快一点,因为\0char不需要再次搜索(它已经在strlen()中)。
- 谢谢。在我的个人实施中,我让它变得更"糟糕"。return memcpy(malloc(len), s, len);,因为我更喜欢分配崩溃而不是分配失败的NULL。
- @Tristopia不引用NULL,不必崩溃;它是未定义的。如果你想确定它会崩溃,写一个emalloc,失败时会调用abort。
- 我知道这一点,但是我的实现保证只在Solaris或Linux上运行(根据应用程序的本质)。
- @崔斯特菲亚:养成以最好的方式做事的习惯是好的。养成使用emalloc的习惯,即使在Solaris或Linux上不需要这样做,这样将来在其他平台上编写代码时也可以使用它。
没有必要重复其他答案,但请注意,strdup()可以从C的角度做任何它想做的事情,因为它不是任何C标准的一部分。但是它是由posix.1-2001定义的。
- strdup()是便携式的吗?不,在非POSIX环境中不可用(无论如何都可以实现)。但是说posix函数可以做任何事情都是很迂腐的。POSIX是另一个和C一样好的标准,甚至更受欢迎。
- @Bluemoon我认为要点是,声明不符合POSIX的C实现仍然可以提供一个strdup函数作为扩展。在这种实现上,不能保证strdup的行为与posix函数相同。我不知道有任何这样的实现,但是合法的非恶意实现可能出于历史原因提供char *strdup(char *),并拒绝通过const char *。
- C标准和POSIX有什么区别?你的意思是,C标准库中不存在它?
- @它们是不同的标准。最好将它们视为无关的,除非您知道特定C函数的标准符合POSIX标准,并且您的编译器/库符合该函数的标准。
来自strdup man:
strdup()函数应返回一个指向新字符串的指针,该字符串是s1指向的字符串的副本。返回的指针可以传递给free()。如果无法创建新字符串,则返回空指针。
strdup()为字符数组执行动态内存分配,包括结束字符' ',并返回堆内存的地址:
1 2 3 4 5 6 7
| 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
} |
所以,它所做的是给我们另一个字符串,与它的参数给出的字符串相同,而不需要我们分配内存。但我们还是需要稍后释放它。
strdup和strndup在符合POSIX的系统中定义为:
1 2
| char *strdup(const char *str);
char *strndup(const char *str, size_t len); |
函数的作用是:为字符串str进行复制,并返回指向它的指针。
指针随后可用作函数free的参数。
如果内存不足,返回NULL并将errno设置为ENOMEM。
strndup()函数最多从字符串str复制len个字符,但始终为空,终止复制的字符串。
它通过运行传入字符串的malloc和strcpy来复制传入的字符串。malloc'ed缓冲区返回给调用方,因此需要对返回值运行free。
声明:
号
相当于(而不是改变指针的事实):
1
| while(*ptr2++ = *ptr1++); |
鉴于:
。
相当于:
因此,如果希望复制的字符串用于另一个函数(在heap部分创建),可以使用strdup,否则strcpy就足够了,
它所做的最有价值的事情是为您提供另一个与第一个字符串相同的字符串,而不需要您自己分配内存(位置和大小)。但是,如前所述,您仍然需要释放它(但也不需要进行数量计算)。
strdup()函数是字符串复制的简写,它将一个参数作为字符串常量或字符串文字,为字符串分配足够的空间,并在分配的空间中写入相应的字符,最后将分配的空间的地址返回给调用例程。
- strdup的参数不需要是字符串常量,它必须是C字符串,即char的以空结尾的数组。