这是使用 strcpy 的好方法吗?

Is this a good way to use strcpy?

我尝试使用strcpy;这是这样做的好方法吗?

char *stringvar;
stringvar = malloc(strlen("mi string") + 1);
strcpy(stringvar, "mi string");
stringvar[strlen("mi string")] = '[=10=]';

你怎么看?

你不需要最后一行

stringvar[strlen("mi string")] = '[=10=]';

strcpy 会为您处理。

在实际代码中,您绝对必须检查 malloc 的 return 值以确保它不是 NULL.

除此之外你的代码没问题。特别是,您在 malloc 的调用中获得了重要的 + 1strlen 给你字符串的长度 包括终止 '[=22=]' 字符,但 strcpy 将添加它,所以你绝对需要为它分配space。

strcpy 的问题——有人说是致命的问题——是在你调用 strcpy 的那一刻,你无法告诉 strcpy 有多大目标数组是。 你有责任 使数组足够大,并避免溢出。 strcpy 本身无法防止缓冲区溢出——当然,如果目标确实溢出,那就是个大问题。

那么问题是,您如何确保——绝对确保——您编写的所有代码中对strcpy的所有调用都是正确的?您如何确保以后修改您的程序的人不会不小心把事情搞砸?

基本上,如果您完全使用 strcpy,您希望安排两个事物紧挨着彼此:

  1. 安排指针变量指向足够 space 用于您要复制到其中的字符串的代码,并且
  2. 实际调用 strcpy 将字符串复制到该指针。

所以你的代码

stringvar = malloc(strlen("mi string") + 1);
strcpy(stringvar, "mi string");

非常接近这个理想。

我知道你的代码只是一个例子,但它确实让我们探讨了这个问题,如果以后有人修改你的程序不小心把事情搞砸了怎么办?如果有人把它改成

怎么办
stringvar = malloc(strlen("mi string") + 1);
strcpy(stringvar, "mi string asombroso");

显然我们遇到了问题。所以要绝对确定我们正在复制的字符串有空间,我认为如果我们正在复制的字符串在变量中就更好了,所以很明显我们正在复制的字符串是我们分配给 space 的 相同的 字符串。

所以这是我对你的代码的改进版本:

char *inputstring = "mi string";
char *stringvar = malloc(strlen(inputstring) + 1);
if(stringvar == NULL) {
    fprintf(stderr, "out of memory\n");
    exit(1);
}
strcpy(stringvar, inputstring);

(不幸的是,检查 malloc 中的 NULL return 妨碍了 strcpy 紧挨着 malloc 呼叫。)

基本上,您的代码是 C 库函数 strdup 的实现,它接受您提供的字符串和 return 在 malloc 内存中的副本。

还有一件事。您担心全部到 malloc 中的 + 1,正如我所说,这是正确的。一个很常见的错误是

stringvar = malloc(strlen(inputstring));
strcpy(stringvar, inputstring);

这无法为 [=39=] 分配 space,因此当 strcpy 添加 [=39=] 时它会溢出已分配的 space,所以这是一个问题.

话虽如此,请确保您不会不小心写

stringvar = malloc(strlen("mi string" + 1));

你看到错误了吗?这是一个非常容易犯的错误,但显然它并没有按照您的意愿去做。

其中只有一个错误:您没有检查 malloc-failure。

除此之外,它是重复的并且容易出错。
而且用终结符覆盖终结符也没用
此外,重复重新计算字符串长度是昂贵的。
无论如何,因为您已经必须确定长度,所以更喜欢 memcpy() over strcpy().

你应该做的是将它提取到一个函数中,我们称它为strdup()(即名称POSIX,下一个C标准给它):

char* strdup(const char* s) {
    size_t n = strlen(s) + 1;
    char* r = malloc(n);
    if (r)
        memcpy(r, s, n);
    return r;
}

char* stringvar = strdup("mi string");
if (!stringvar)
    handle_error();

发布的代码存在一些问题:

  • 您不检查 malloc() 是否成功:如果 malloc() 失败并且 returns NULL,将此空指针传递给 strcpy 具有未定义的行为。
  • 最后一条语句 stringvar[strlen("mi string")] = '[=17=]'; 没用:strcpy 确实 复制源字符串末尾的空终止符,使目标数组成为正确的C弦.

这是更正后的版本:

#include <stdlib.h>
#include <string.h>
...
    char *stringvar;
    if ((stringvar = malloc(strlen("mi string") + 1)) != NULL)
        strcpy(stringvar, "mi string");

请注意,存储分配大小而不使用 strcpy:

会稍微好一点
    char *stringvar;
    size_t size = strlen("mi string") + 1;
    if ((stringvar = malloc(size)) != NULL)
        memcpy(stringvar, "mi string", size);

事实上,使用 strdup() 会更简单、更安全,可在 POSIX 兼容系统上使用,完全执行上述步骤:

    char *stringvar = strdup("mi string");