strdup() - 它在 C 中做了啥?

Posted

技术标签:

【中文标题】strdup() - 它在 C 中做了啥?【英文标题】:strdup() - what does it do in C?strdup() - 它在 C 中做了什么? 【发布时间】:2010-09-20 03:33:16 【问题描述】:

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

【问题讨论】:

还有 strdupa()(在 GNU C 库中),一个很好的函数,类似于 strdup(),但在堆栈上分配内存。您的程序不需要像 strdup() 那样显式释放内存,当您退出调用 strdupa() 的函数时,它将自动释放 strdupa 很危险,除非您已经确定 strlen 非常小,否则不应使用。但是你可以在堆栈上使用一个固定大小的数组。 @slacker 谷歌翻译没有帮助...strdup/strdupa 在波兰语中是什么意思? @haneefmubarak here 这里是strdup和strcpy的区别***.com/questions/14020380/strcpy-vs-strdup 【参考方案1】:

来自strdup man:

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

【讨论】:

【参考方案2】:

它通过运行传入字符串的 ma​​llocstrcpy 来复制传入的字符串。malloc 的缓冲区返回给调用者,因此需要在返回值上运行 free

【讨论】:

【参考方案3】:

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

【讨论】:

【参考方案4】:

听起来确实如此,假设您习惯了 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 设置为ENOMEMmalloc 在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> 找到:

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

【讨论】:

值得注意的是,正如 Pax 的示例实现所暗示的那样,strdup(NULL) 是未定义的,您不能期望它以任何可预测的方式表现。 另外,我认为 malloc() 会设置 errno,因此您不必自己设置。我想。 @Alcot, strdup 适用于您希望为字符串副本分配堆内存的情况。否则你必须自己做。如果你已经一个足够大的缓冲区(malloc'ed 或其他),是的,使用strcpy @acgtyrant:如果按照标准,您的意思是 ISO 标准(真正的 C 标准),不,它不是其中的一部分。它 POSIX 标准的一部分。但是,尽管不是 ISO C 的官方部分,但仍有很多 C 实现 提供它。但是,即使它们没有,这个答案中的五行应该绰绰有余. 好点,@chux,ISO 仅要求 EDOM, EILSEQ, ERANGE 作为必需的错误代码。已更新答案以解决此问题。【参考方案5】:

没有必要重复其他答案,但请注意,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 标准库中不存在? @KorayTugay 他们是不同的标准。最好将它们视为不相关的,除非您知道特定 C 函数的标准符合 POSIX 标准,并且您的编译器/库符合该函数的标准。【参考方案6】:
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() 已经搜索过了)。

【讨论】:

谢谢。在我个人的实现中,我让它变得“更糟”。 return memcpy(malloc(len), s, len);,因为我更喜欢分配崩溃而不是分配失败时的NULL @tristopia 取消引用 NULL 不必崩溃;它是未定义的。如果你想确保它崩溃,写一个emalloc,它在失败时调用abort 我知道,但我的实现只能在 Solaris 或 Linux 上运行(根据应用程序的本质)。 @tristopia:养成以最佳方式做事的习惯是件好事。养成使用 emalloc 的习惯,即使在 Solaris 或 Linux 上没有必要,这样您将来在其他平台上编写代码时也会使用它。【参考方案7】:

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

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

【讨论】:

【参考方案8】:

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

【讨论】:

strdup的参数不必是字符串常量,它必须是C字符串,即char的空终止数组。【参考方案9】:

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

char *strdup(const char *str);
char *strndup(const char *str, size_t len);

strdup() 函数为 字符串str,进行复制,并返回一个指向它的指针。

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

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

strndup() 函数最多从字符串str 复制len 字符,始终为空,以终止复制的字符串。

【讨论】:

【参考方案10】:

声明:

strcpy(ptr2, ptr1);

相当于(除了这会改变指针的事实):

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

鉴于:

ptr2 = strdup(ptr1);

相当于:

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

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

【讨论】:

以上是关于strdup() - 它在 C 中做了啥?的主要内容,如果未能解决你的问题,请参考以下文章

Protocol* x = @protocol(aProtocolName) 在目标 c 中做了啥?

(一元)* 运算符在这段 Ruby 代码中做了啥?

ffmpeg.c pts 和 dts 是啥?这个代码块在 ffmpeg.c 中做了啥?

#ifdef _CH_ 预处理器指令在 C 中做了啥?

tf.nn.conv2d 在 tensorflow 中做了啥?

print(S[::2],[1::2]) 这行在下面的程序中做了啥[重复]