是否有函数可以将字符串复制到内存中的新空间 [关闭]

Is there a function(s) to copy a string into a new space in memory [closed]

提问人:Frank Okey 提问时间:8/10/2023 最后编辑:chqrlieFrank Okey 更新时间:8/10/2023 访问量:99

问:


想改进这个问题吗?通过编辑这篇文章添加详细信息并澄清问题。

4个月前关闭。

如果我想在 C 编程中将字符串复制到内存中的新空间中,我可以使用哪些语句来为它保留足够的空间?"Best School"

我试过使用它:

malloc(strlen("Best School") + 1)

这也

malloc(sizeof("Best School"))
c malloc 堆内存 释放 calloc

评论

5赞 Ted Lyngmo 8/10/2023
strdup将是我的解决方案。
1赞 Some programmer dude 8/10/2023
虽然不是标准的 C 函数,但 POSIX(Linux 和 macOS)和 Windows 都具有分配复制字符串的函数。strdup
2赞 Ted Lyngmo 8/10/2023
@Someprogrammerdude 不过,这将是 C23 的标准功能。最后:-)
2赞 Some programmer dude 8/10/2023
最后,关于您的问题本身:请阅读帮助页面,参加 SO 导览,并阅读如何提问。以及如何写出“完美”的问题,尤其是它的清单。您的问题似乎是关于为什么在分配内存时需要 +1,而不是关于复制本身。这使您的标题具有误导性。
2赞 Lundin 8/10/2023
就实际的 malloc 而言,您的两个版本都是正确的,因此问题出在其他地方。您不显示实际的复制。请发布一个完整的示例。

答:

3赞 chqrlie 8/10/2023 #1

分配内存块并将以 null 结尾的字符串复制到其中的最简单、最安全的方法是:

    char *ptr = strdup("Best School");

strdup()自 POSIX 标准成立以来一直是 POSIX 标准的一部分,并最终在 C23 中成为标准 C 的一部分。它在大多数系统上都可用,可以这样定义:<string.h>

#include <stdlib.h>

char *strdup(const char *s) {
    size_t size = strlen(s) + 1;
    char *p = malloc(size);
    return p ? memcpy(p, s, size) : NULL;
}

或者,您可以使用 ,并直接:mallocstrlenstrcpy

malloc分配给定大小的块内存。内存未初始化,其内容不确定,因此如果分配成功,则必须将字符串复制到其中,包括 null 终止符 ()。 是具有 12 个字节的以 null 结尾的字符串:11 个字符加上一个 null 终止符字节。'\0'"Best school"

    // add 1 for the null terminator
    char *ptr = malloc(strlen("Best school") + 1);
    if (ptr) strcpy(ptr, "Best school");

对于字符串文字,您甚至可以使用:sizeof

    // sizeof includes the null terminator in a string literal
    char *ptr = malloc(sizeof "Best school");
    if (ptr) strcpy(ptr, "Best school");

但上述两种解决方案都容易出错,因为:

  • 人们很容易忘记为 null 终止符分配或复制额外的字节。此错误会导致未定义的行为,但由于分配粒度的原因,可能会在一段时间内未被发现:例如,分配 11 个字节可能会返回一个 16 字节的块,而第 12 个字节可能恰好是空字节,尤其是在以前未使用过此内存的情况下。这种不明确的行为是狡猾的,会在最糟糕的时候咬人。"Best school"
  • 该版本仅适用于字符串文字!如果要分配只有指针指向的字符串的副本,则将计算指针的大小,而不是字符串的大小,从而导致除最短字符串之外的所有字符串都出现未定义的行为。此解决方案适用于问题中的示例,但应忽略。sizeofsizeof(ptr)

推荐的解决方案是 。strdup

0赞 0___________ 8/10/2023 #2

您需要分配内存并复制原始字符串。我会建议在开始时(出于教育目的)编写所有函数。下面是一个示例

size_t mystrlen(const char *str)
{
    char *end = str;
    if(str) while(*end) end++;
    return end - str;
}

void *mymemcpy(void *dest, const void *src, size_t len)
{
    if(dest && src)
    {
        const unsigned char *ucsrc = src;
        unsigned char *ucdest = dest;
        while(len--) *ucdest++ = *ucsrc++;
    }
    return dest;
}

char *mystrdup(const char *str)
{
    char *newstr = NULL;
    size_t len = 0;
    if(str)
    {
        len = mystrlen(str) + 1;
        newstr = malloc(len);
        if(newstr)
        {
            mymmemcpy(newstr, str, len);
        }
    }
    return newstr;
}

评论

1赞 chqrlie 8/10/2023
好教!我想说两句话:标准函数没有空指针检查,更重要的是,您只复制字节而不是:)使用时不容易出错。lenlen + 1size_t size = mystrlen(str) + 1;
0赞 chqrlie 8/10/2023
恕我直言,该名称具有误导性,因为该变量不包含 返回的字符串的长度lenmystrlen
0赞 0___________ 8/10/2023
缓冲区的@chqrlie长度不是字符串
0赞 chqrlie 8/10/2023
我理解这一点,但在上下文中,这有点误导,正如您在第一篇文章中亲身经历的那样。