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

发布于 2024-07-08 00:52:36 字数 43 浏览 7 评论 0原文

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

What is the purpose of the strdup() function in C?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

呆萌少年 2024-07-15 00:52:36

正如它听起来的那样,假设您习惯了 C 和 UNIX 分配单词的缩写方式,它重复字符串 :-)

请记住,它实际上不是一部分当前 (C17) 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
}

换句话说:

  1. 它尝试分配足够的内存保存旧字符串(加上“\0”字符来标记字符串的结尾)。

  2. 如果分配失败,则会将 errno 设置为 ENOMEM 并立即返回 NULL。 将 errno 设置为 ENOMEMmalloc 在 POSIX 中执行的操作,因此我们不需要在 strdup 中显式执行此操作代码>. 如果您符合 POSIX 标准,ISO C 实际上并不强制要求 ENOMEM 的存在,因此我没有将其包含在此处(b).

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

请记住这是概念定义。 任何值得薪水的库编写者都可能提供针对正在使用的特定处理器的高度优化的代码。

另一件需要记住的事情是,根据草案 N2912,此目前预计将与 strndup 一起纳入标准的 C2x 迭代中文档的


(a) 但是,以 str 和小写字母开头的函数由标准保留以供将来使用。 来自C11 7.1.3 保留标识符

每个标头都声明或定义其关联子条款中列出的所有标识符,并且可以选择声明或定义其关联的未来库方向子条款中列出的标识符。*

string.h 的未来方向 可以在 C11 7.31.13 字符串处理 中找到:

strmemwcs 开头的函数名称和小写字母可以添加到 中的声明中 标头。

因此,如果您想安全的话,您可能应该将其称为其他名称。


(b) 更改基本上是将 if (d == NULL) return NULL; 替换为:

if (d == NULL) {
    errno = ENOMEM;
    return NULL;
}

(c) 请注意,我使用 < code>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
}

Exactly what it sounds like, assuming you're used to the abbreviated way in which C and UNIX assigns words, it duplicates strings :-)

Keeping in mind it's actually not part of the current (C17) ISO C standard itself(a) (it's a POSIX thing), it's effectively doing the same as the following code:

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
}

In other words:

  1. It tries to allocate enough memory to hold the old string (plus a '\0' character to mark the end of the string).

  2. If the allocation failed, it sets errno to ENOMEM and returns NULL immediately. Setting of errno to ENOMEM is something malloc does in POSIX so we don't need to explicitly do it in our strdup. If you're not POSIX compliant, ISO C doesn't actually mandate the existence of ENOMEM so I haven't included that here(b).

  3. Otherwise the allocation worked so we copy the old string to the new string(c) and return the new address (which the caller is responsible for freeing at some point).

Keep in mind that's the conceptual definition. Any library writer worth their salary may have provided heavily optimised code targeting the particular processor being used.

One other thing to keep in mind, it looks like this is currently slated to be in the C2x iteration of the standard, along with strndup, as per draft N2912 of the document.


(a) However, functions starting with str and a lower case letter are reserved by the standard for future directions. From 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.*

The future directions for string.h can be found in C11 7.31.13 String handling <string.h>:

Function names that begin with str, mem, or wcs and a lowercase letter may be added to the declarations in the <string.h> header.

So you should probably call it something else if you want to be safe.


(b) The change would basically be replacing if (d == NULL) return NULL; with:

if (d == NULL) {
    errno = ENOMEM;
    return NULL;
}

(c) Note that I use strcpy for that since that clearly shows the intent. In some implementations, it may be faster (since you already know the length) to use memcpy, as they may allow for transferring the data in larger chunks, or in parallel. Or it may not :-) Optimisation mantra #1: "measure, don't guess".

In any case, should you decide to go that route, you would do something like:

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
}
酒解孤独 2024-07-15 00:52:36
char * strdup(const char * s)
{
  size_t len = 1+strlen(s);
  char *p = malloc(len);

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

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

编辑:根据一些文档,当分配失败时,strdup()errno设置为ENOMEM

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

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

Maybe the code is a bit faster than with strcpy() as the \0 char doesn't need to be searched again (It already was with strlen()).

EDIT: according to some documents, strdup() sets errno to ENOMEM when allocation fails.

倒数 2024-07-15 00:52:36

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

No point repeating the other answers, but please note that strdup() can do anything it wants from a C perspective, since it is not part of any C standard. It is however defined by POSIX.1-2001.

儭儭莪哋寶赑 2024-07-15 00:52:36

来自strdup man

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

From strdup man:

The strdup() function shall return a pointer to a new string, which is a duplicate of the string pointed to by s1. The returned pointer can be passed to free(). A null pointer is returned if the new string cannot be created.

梦魇绽荼蘼 2024-07-15 00:52:36

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() does dynamic memory allocation for the character array including the end character '\0' and returns the address of the heap memory:

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
}

So, what it does is give us another string identical to the string given by its argument, without requiring us to allocate memory. But we still need to free it, later.

柠檬心 2024-07-15 00:52:36

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

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

strdup() 函数 为
string str,进行复制,并返回指向它的指针。

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

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

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

strdup and strndup are defined in POSIX compliant systems as:

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

The strdup() function allocates sufficient memory for a copy of the
string str, does the copy, and returns a pointer to it.

The pointer may subsequently be used as an argument to the function free.

If insufficient memory is available, NULL is returned and errno is set to
ENOMEM.

The strndup() function copies at most len characters from the string str always null terminating the copied string.

久而酒知 2024-07-15 00:52:36

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

It makes a duplicate copy of the string passed in by running a malloc and strcpy of the string passed in. The malloc'ed buffer is returned to the caller, hence the need to run free on the return value.

南风几经秋 2024-07-15 00:52:36

语句:

strcpy(ptr2, ptr1);

相当于(除了改变指针这一事实之外):

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

而:

ptr2 = strdup(ptr1);

相当于:

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

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

The statement:

strcpy(ptr2, ptr1);

is equivalent to (other than the fact this changes the pointers):

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

Whereas:

ptr2 = strdup(ptr1);

is equivalent to:

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

So, if you want the string which you have copied to be used in another function (as it is created in heap section), you can use strdup, else strcpy is enough,

帅冕 2024-07-15 00:52:36

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

The most valuable thing it does is give you another string identical to the first, without requiring you to allocate memory (location and size) yourself. But, as noted, you still need to free it (but which doesn't require a quantity calculation, either.)

一萌ing 2024-07-15 00:52:36

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

The strdup() function is a shorthand for string duplicate, it takes in a parameter as a string constant or a string literal and allocates just enough space for the string and writes the corresponding characters in the space allocated and finally returns the address of the allocated space to the calling routine.

鹿! 2024-07-15 00:52:36

使用 strdup 您可以获得字符串 word 或任何字符串的可修改副本。 这样,您就可以更改其内容,而不会遇到更换硬盘的问题。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
    const char* original = "Hello, World!";
    char *copy = strdup(original); // Create a copy

    if (copy != NULL) {
        // Modify the copy
        strcpy(copy, " Again Hello World \n");

        printf("Original: %s\n", original); 
        printf("Copy: %s\n", copy);         

        free(copy); 
    } else {
        printf("Memory allocation failed.\n");
    }

    return 0;
}

Using strdup you can get a modifiable copy of the string word or any string. In this way, you can change its contents without encountering the problems of replacing the hard memory.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
    const char* original = "Hello, World!";
    char *copy = strdup(original); // Create a copy

    if (copy != NULL) {
        // Modify the copy
        strcpy(copy, " Again Hello World \n");

        printf("Original: %s\n", original); 
        printf("Copy: %s\n", copy);         

        free(copy); 
    } else {
        printf("Memory allocation failed.\n");
    }

    return 0;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文