strcpy() 和 strncpy() 都是 C 语言中的字符串复制函数,用于将一个字符串的内容复制到另一个字符串中,但它们有一些关键的区别。 现代 C 编程中,建议使用 snprintf() 或 strlcpy()(如果可用)等更安全的函数,它们更容易避免这些问题。

1、strcpy()

strcpy() 将源字符串 src 复制到目标字符串 dest 中,包括字符串的结尾 \0null 字符)。但strcpy() 不会检查目标数组的大小,因此如果目标数组没有足够的空间来存放源字符串,它可能会导致缓冲区溢出,这是一种常见的安全漏洞。

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

int main() {
    // 定义目标数组和源字符串
    char dest[20];
    const char *src = "Hello, World!";
    
    // 使用 strcpy 将 src 复制到 dest
    strcpy(dest, src);

    // 输出 dest 字符串
    printf("Copied string: %s\n", dest);

    return 0;
}

2、strncpy()

strncpy() 将最多 n 个字符从源字符串 src 复制到目标字符串 dest。如果源字符串的长度小于 n,则会在目标字符串中填充多余的 \0 字符,直到复制了 n 个字符为止。但strncpy() 不一定会在目标字符串的末尾添加 \0,如果源字符串长度大于或等于 n,目标字符串不会以 \0 结尾,因此需要特别小心。

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

int main() {
    char dest[20];          // 目标字符数组,大小为 20
    const char *src = "Hello";  // 源字符串

    // 使用 strncpy 复制最多 10 个字符
    strncpy(dest, src, 10);

    // 确保目标字符数组以 '\0' 结尾
    dest[19] = '\0';  // 将最后一个字符设置为 '\0',防止未终止的字符串

    // 打印目标字符数组
    printf("Destination string: %s\n", dest);

    return 0;
}

3、strcpy() 和 strncpy() 的区别

strcpy() 将一个字符串从源复制到目标,直到遇到字符串结束符 \0。如果目标数组的大小不够大,就会导致内存越界问题,造成潜在的安全漏洞。

strncpy() 将最多 n 个字符从源复制到目标。如果源字符串长度小于 n,则在目标字符串末尾添加空字符 \0;如果源字符串长度大于或等于 n,则目标字符串不会添加 \0,这可能会导致字符串没有正确结束。

strcpy() 的问题在于没有边界检查,容易导致缓冲区溢出,从而引发安全漏洞。strncpy() 提供了最大字符数的限制,从而降低了溢出风险,但仍然有其缺陷,比如没有自动添加 \0 结束符,可能需要额外的处理。

在实践中,使用 strncpy() 时应该小心,确保目标字符串正确结束,并且目标缓冲区足够大。

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

int main() {
    char src[] = "Hello, World!";
    char dest1[20];
    char dest2[10];

    // 使用 strcpy()
    strcpy(dest1, src);
    printf("dest1 after strcpy: %s\n", dest1);  // 输出: Hello, World!

    // 使用 strncpy()
    strncpy(dest2, src, sizeof(dest2) - 1);  // 保证 dest2 不会溢出
    dest2[sizeof(dest2) - 1] = '\0';  // 确保字符串以 null 结尾
    printf("dest2 after strncpy: %s\n", dest2);  // 输出: Hello

    return 0;
}