C语言复制字符串

例子

指针分配不复制字符串

您可以使用=运算符复制整数,但是不能使用该=运算符复制C中的字符串。C中的字符串表示为带有终止空字符的字符数组,因此使用该=运算符将仅保存以下地址(指针)一个字符串。

#include <stdio.h>

int main(void) {

    int a = 10, b;

    char c[] = "abc", *d;

    b = a; /* Integer is copied */

    a = 20; /* Modifying a leaves b unchanged - b is a 'deep copy' of a */

    printf("%d %d\n", a, b); /* "20 10" will be printed */

    d = c; 

    /* Only copies the address of the string - 

    there is still only one string stored in memory */

    

    c[1] = 'x';

    /* Modifies the original string - d[1] = 'x' will do exactly the same thing */

    printf("%s %s\n", c, d); /* "axc axc" will be printed */

    return 0;

}

上例进行编译是因为我们使用char *d而不是char d[3]。使用后者会导致编译器错误。您不能在C中分配给数组。

#include <stdio.h>

int main(void) {

    char a[] = "abc";

    char b[8];

    b = a; /* compile error */

    printf("%s\n", b);

    return 0;

}

使用标准函数复制字符串

strcpy()

要实际复制字符串,strcpy()可以在中使用function string.h。复制之前,必须为目标分配足够的空间。

#include <stdio.h>

#include <string.h>

int main(void) {

    char a[] = "abc";

    char b[8];

    strcpy(b, a); /* think "b special equals a" */

    printf("%s\n", b); /* "abc" will be printed */

    return 0;

}

C99

snprintf()

为避免缓冲区溢出,snprintf()可以使用。这不是最佳解决方案性能,因为它必须解析模板字符串,但是它是用于复制标准库中易于使用的字符串的唯一缓冲区限制安全功能,无需任何额外步骤即可使用它。

#include <stdio.h>

#include <string.h>

int main(void) {

    char a[] = "012345678901234567890";

    char b[8];

#if 0

    strcpy(b, a); /* causes buffer overrun (undefined behavior), so do not execute this here! */

#endif

    snprintf(b, sizeof(b), "%s", a); /* does not cause buffer overrun */

    printf("%s\n", b); /* "0123456" will be printed */

    return 0;

}

strncat()

具有更好性能的第二种选择是使用strncat()(的缓冲区溢出检查版本strcat())-它采用第三个参数,告诉它要复制的最大字节数:

char dest[32];

dest[0] = '\0';

strncat(dest, source, sizeof(dest) - 1);

    /* copies up to the first (sizeof(dest) - 1) elements of source into dest,

    then puts a \0 on the end of dest */

注意此公式的使用sizeof(dest) - 1; 这很关键,因为strncat()总是添加一个空字节(好的),但不将其计入字符串的大小(造成混淆和缓冲区覆盖的原因)。

还要注意,替代方案(在非空字符串后进行连接)更加烦人。考虑:

char dst[24] = "Clownfish: ";

char src[] = "Marvin and Nemo";

size_t len = strlen(dst);

strncat(dst, src, sizeof(dst) - len - 1);

printf("%zu: [%s]\n", strlen(dst), dst);

输出为:

23: [Clownfish: Marvin and N]

但是请注意,指定为长度的大小不是目标数组的大小,而是其中剩余的空间量,不计入终端空字节。这可能会导致严重的覆盖问题。这也有点浪费;要正确指定length参数,您知道目标中数据的长度,因此您可以在现有内容的末尾指定空字节的地址,strncat()以免重新扫描:

    strcpy(dst, "Clownfish: ");

    assert(len < sizeof(dst) - 1);

    strncat(dst + len, src, sizeof(dst) - len - 1);

    printf("%zu: [%s]\n", strlen(dst), dst);

这将产生与以前相同的输出,但是strncat()不必dst在开始复制之前扫描现有内容。

strncpy()

最后一个选项是strncpy()功能。尽管您可能认为它应该排在第一位,但这是一个具有欺骗性的功能,它具有两个主要陷阱:

  1. 如果通过复制strncpy()达到缓冲区限制,则不会写入终止的空字符。

  2. strncpy() 始终完全填充目标,必要时使用空字节。

(这种古怪的实现是历史性的,最初用于处理UNIX文件名)

唯一正确的使用方法是手动确保终止符为空:

strncpy(b, a, sizeof(b)); /* the third parameter is destination buffer size */

b[sizeof(b)/sizeof(*b) - 1] = '\0'; /* terminate the string */

printf("%s\n", b); /* "0123456" will be printed */

即使这样,如果您有一个大缓冲区,strncpy()由于额外的空填充,使用它的效率也会非常低下。

以上是 C语言复制字符串 的全部内容, 来源链接: utcz.com/z/354103.html

回到顶部