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

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

431940 次浏览

第6行的人:

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

它通过运行传入字符串的malloc拷贝字符串来复制传入的字符串。malloc'ed缓冲区返回给调用者,因此需要对返回值运行免费的

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

就像它听起来一样,假设你习惯了C和UNIX分配单词的缩写方式,它< >强重复字符串< / >强:-)

请记住,它实际上不是当前(C17) ISO C标准本身__abc0的一部分(它是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. 如果分配失败,它将errno设置为ENOMEM并立即返回NULL。将errno设置为ENOMEMmalloc在POSIX中所做的,因此我们不需要在strdup中显式地这样做。如果你是 POSIX兼容的,ISO C实际上并不要求存在ENOMEM,所以我没有在这里包含它。

  3. 否则,分配正常,所以我们将旧字符串复制到新的string(c)并返回新地址(调用者负责在某个时刻释放该地址)。

记住这是概念上的定义。任何有价值的库作者都可能针对所使用的特定处理器提供了大量优化的代码。

另一件需要记住的事情是,根据文档的草案N2912,这个目前与strndup一起被安排在标准的C2x迭代中。


然而,以str和小写字母开头的函数将被标准保留以备将来使用。从C11 7.1.3 Reserved identifiers:

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

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

strmemwcs和小写字母开头的函数名可以添加到<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()可以从C的角度做任何它想做的事情,因为它不是任何C标准的一部分。但是,POSIX.1-2001定义了它。

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


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

也许代码比使用strcpy()更快一点,因为\0字符不需要再次搜索(它已经使用了strlen())。

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
}

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

strdup()函数是字符串重复的简写,它接受一个参数作为字符串常量或字符串字面量,并为字符串分配足够的空间,并在分配的空间中写入相应的字符,最后将分配的空间的地址返回给调用例程。

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

char *strdup(const char *str);
char *strndup(const char *str, size_t len);
第6行的)函数为类的副本分配足够的内存

. string str,执行复制,并返回指向它的指针

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

如果可用内存不足,则返回NULL,并将errno设置为 ENOMEM . < / p >

strndup ()函数从字符串str复制最多len个字符,总是null,终止复制的字符串。

声明:

strcpy(ptr2, ptr1);

等价于(除了会改变指针):

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

而:

ptr2 = strdup(ptr1);

等价于:

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

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