关于function:strdup() – 它在C中做了什么?

strdup() - what does it do in C?

在C中,strdup()函数的用途是什么?


这听起来很像,假设您习惯了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设置为ENOMEMmalloc在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
    }


    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()中)。


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


    来自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
    }

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


    strdupstrndup在符合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
    strcpy(ptr2, ptr1);

    相当于(而不是改变指针的事实):

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

    鉴于:

    1
    ptr2 = strdup(ptr1);

    相当于:

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

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


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


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