C语言中的'memdup'函数是什么?

15

在C语言中,你可以使用strdup函数来简洁地分配一个缓冲区并将一个字符串复制到其中。但就我所知,对于一般的内存操作,没有类似的函数。例如,我无法像这样说:

TBD

struct myStruct *foo = malloc(sizeof(struct myStruct));
fill_myStruct(foo);

struct myStruct *bar = memdup(foo, sizeof(struct myStruct));
// bar is now a reference to a new, appropriately sized block of memory,
//   the contents of which are the same as the contents of foo

那么我的问题有三个:

  1. 是否有一些像这样的标准库函数,我不知道吗?
  2. 如果没有,是否有一种简洁并且最好是标准的方法来完成这个任务,而不需要显式调用 mallocmemcpy
  3. C语言为什么包含 strdup 而不包含 memdup

2
strdup不就是一个malloc和一个memcpy吗? - Marlon
3
这是两个函数调用(malloc()memcpy())。看起来有点微不足道,不值得为此写一个函数。如果你想避免字符串被多次遍历,strdup() 函数就会稍微复杂一些。 - Mysticial
3
你看过哪个strdup()的实现不需要精确两次遍历输入字符串?(一次用来计算缓冲区大小,一次用来复制) - Billy ONeal
2
我的目的主要是为了代码可读性 - 我想从 struct myStruct *bar = (struct myStruct *)malloc(sizeof(struct myStruct)); memcpy(bar, foo, sizeof(struct myStruct)); 转换成一个相对简短的单行代码,让人一眼就能明白正在发生什么。 - Dan
4
@Dan 不要用malloc的返回值进行类型转换。除此之外,C语言没有包含strdup函数。不过,在POSIX系统中,该函数已经被广泛应用。但是不能保证它在所有系统上都可用。而struct myStruct *bar = malloc(sizeof *bar); *bar = *foo;这种写法看起来还不错,对吧? - Daniel Fischer
显示剩余4条评论
6个回答

19

你可以用一个简单的函数来实现它:

void* memdup(const void* mem, size_t size) { 
   void* out = malloc(size);

   if(out != NULL)
       memcpy(out, mem, size);

   return out;
}

4
这不回答任何三个具体问题中的一个。 - Ayxan Haqverdili

7

在GNU Gnulib的xalloc.h中有一个void *xmemdup(void const *p, size_t s)函数。

请注意,如果内存不足,它会调用xalloc_die


2
这是唯一一个实际回答了任何问题的响应。 - Greg Kennedy

0

你可能只需要自己定义memdup()函数,然后像已经建议的那样在代码中简单地使用它。下面是我编写的函数版本。

void *memdup(const void *src, size_t n)
{
    void *dest;

    dest = malloc(n);
    if (dest == NULL)
            return NULL;

    return memcpy(dest, src, n);
}

关于讨论 memdup() 是否太琐碎甚至是多余的,我不这么认为。它在代码中复制结构体非常有用。C标准库的ANSI/ISO和POSIX标准都包含了很多方便的函数,但不幸的是没有这个。

示例:使用 memdup() 重新实现 strdup()

char *strdup(const char *src)
{
    return memdup(src, strlen(src) + 1);
}

示例:使用memdup()复制对象。

int some_function(const struct some_struct *some_const_data)
{
    struct some_struct *my_mutable_copy;

    my_mutable_copy = memdup(some_const_data, sizeof *some_const_data);
    if (my_mutable_copy == NULL)
        return -1;

    ...

    return 0;
}

2
@Hooper 嗯,实际上NUL字节是从以NUL结尾的源字符串复制而来。 - Pavel Šimerda

0
为什么C语言中有`strdup`却没有`memdup`?
在C23之前,`strdup`不是C标准库函数,但它是POSIX函数。你可以注意到这样的模式,在dynamic memory TR之前,除了用于分配内存的函数外,没有任何函数会返回指向动态分配的内存缓冲区的指针,以供稍后调用`free`(getdelim、getline、strdup、strndup都不是标准函数)。我不知道这个设计选择背后的原因,但我猜测`memdup`也没有被实现,可能是出于相同的原因。
有没有类似的标准库函数我不知道?
没有。
如果没有的话,有没有一种简洁且最好是标准的方法,可以在没有显式调用`malloc`和`memcpy`的情况下完成这个操作?
没有。

-2

strdup函数读取并复制空终止字符串上的空值。然而,普通数据没有这样的分隔符,因此您需要提供要复制的数据长度。


2
这是正确的答案。strdup存在的原因不仅仅是将两个调用包装成一个,而是因为扫描空字节的逻辑,因为进行malloc+strcpy会导致冗余的strlen。对于memdup来说,这是不必要的,这就是为什么当一个简单的malloc + memcpy足够时,它并没有特别的理由。 - rdb
7
@rdb提到,像memcpy一样,memdup也可以接受一个大小参数。但我认为这并不是一个令人信服的回答。 - tvanfosson
2
@rdb 是的,strdup 将三个调用包装在一起,而 strlen 调用肯定不是多余的——你需要以某种方式确定字符串的长度(或所需内存量)。通常情况下,在复制字符串之前需要分配内存,在这种情况下,你需要按顺序调用 strlenmallocstrcpy - skyking
使用strlen+malloc+memcpy可能更有效率。 - Toby Speight

-6
制作任意内存结构的副本并不像复制字符串那样直截了当。如果这个结构包含指向其他结构体(比如字符串)的指针,你该如何处理?“复制”这样的结构是什么意思?与字符串不同,对于这个问题并没有一个正确的答案。在这种情况下,最好让应用程序开发者根据他们的用例创建制作结构体副本的机制,而不是通过假装有一种可以处理它的规范方式来混淆问题。

12
有几个函数可以用于内存操作,包括memcpy()、memcmp()、memmem()和memchr()。是否编写一个名为void * memdup(const void * mem, size_t size)的函数也是有意义的?它将复制指定大小的内存,并返回指向新分配的内存的指针。 - user666412
7
如前所述,它的工作方式与memcpy()相同。它旨在复制一个内存区域,该区域恰好是一个数据结构。 - user666412
11
除了memdup不会复制一个结构体之外,按名称而言,它会复制一块内存区域。它是memdup,而不是datastructuredup。请注意,本句中的“duplicate”指“复制”,并非“重复”的意思。 - Taywee
8
@Tim Ring: ...同样的问题也适用于简单的赋值操作。低级别的memdup不能正确地复制一个结构体,这个事实不能被有意义地用作反对memdup的论据。这个回答只是一种试图用不必要的噪音填充问题的煽动性言辞。 - AnT stands with Russia
3
如果我能获得一美元每当我在StackOverflow上看到这种尝试,那该多好啊... (注意:为了使翻译更通顺,我将@AnT翻译为“我”,因为上下文暗示了他是说话者自己) - user541686
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接