ZetCode

C strcpy_s 函数

最后修改:2025 年 4 月 8 日

字符串操作在 C 编程中是基础性的,而 strcpy_s 是比 strcpy 更安全的字符串复制替代品。本教程将深入介绍 strcpy_s,包括其语法、用法以及相对于传统字符串函数的优势。我们将探讨实际示例,并讨论何时使用此更安全的函数。理解 strcpy_s 有助于防止缓冲区溢出并提高程序安全性。

什么是 strcpy_s?

strcpy_s 函数将一个以 null 结尾的字符串从源复制到目标,并进行边界检查。它是 C11 附录 K 的一部分,接受三个参数:目标指针、目标大小和源指针。strcpy_s 通过验证目标是否有足够的空间来防止缓冲区溢出。与 strcpy 不同,它在失败时返回一个错误代码。这使其对于安全关键型应用程序更加安全。

为什么使用 strcpy_s 而不是 strcpy?

传统的 strcpy 不安全,因为它不检查缓冲区大小,可能导致缓冲区溢出。strcpy_s 添加了运行时约束检查以防止这些漏洞。它需要指定目标缓冲区大小,并为无效操作返回错误代码。虽然并非普遍可用,但在针对安全环境时推荐使用。在安全至关重要的地方,始终优先使用 strcpy_s

基本的 strcpy_s 用法

此示例演示了使用 strcpy_s 的基本字符串复制。

basic_copy.c
#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
#include <string.h>

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

    // Safe string copy
    errno_t result = strcpy_s(dest, sizeof(dest), src);

    if (result == 0) {
        printf("Copied successfully: %s\n", dest);
    } else {
        printf("Error copying string\n");
    }

    return 0;
}

在这里,strcpy_s 将字符串从 src 复制到 dest,并进行边界检查。目标大小指定为 sizeof(dest) 以确保安全。该函数在成功时返回零,在失败时返回非零。此示例检查返回值以正确处理错误。在使用安全函数时,始终验证结果。

处理小型缓冲区

此示例显示了 strcpy_s 如何防止缓冲区溢出。

small_buffer.c
#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
#include <string.h>

int main() {
    char src[] = "This string is too long";
    char dest[10];

    // Attempt to copy to small buffer
    errno_t result = strcpy_s(dest, sizeof(dest), src);

    if (result != 0) {
        printf("Error %d: Buffer too small\n", result);
        return 1;
    }

    printf("Copied: %s\n", dest);
    return 0;
}

此代码演示了 strcpy_s 对缓冲区溢出的防护。目标缓冲区对于源字符串来说太小了。strcpy_s 检测到这一点并返回一个错误代码,而不是导致未定义行为。程序检查返回值并优雅地处理错误。这是比传统 strcpy 的重大改进。

复制到动态分配的内存

此示例显示了将字符串安全地复制到动态分配的内存中。

dynamic_copy.c
#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main() {
    char src[] = "Dynamic allocation test";
    char *dest = malloc(50);

    if (dest == NULL) {
        printf("Memory allocation failed\n");
        return 1;
    }

    // Safe copy to dynamic memory
    errno_t result = strcpy_s(dest, 50, src);

    if (result == 0) {
        printf("Copied: %s\n", dest);
    } else {
        printf("Copy failed\n");
    }

    free(dest);
    return 0;
}

在这里,strcpy_s 将字符串复制到动态分配的内存中。目标大小作为分配的缓冲区大小明确提供。程序同时检查内存分配成功和复制操作成功。始终记得在使用完动态分配的内存后释放它。这种方法结合了内存安全和字符串操作安全。

将 strcpy_s 与结构一起使用

此示例演示了在结构中使用 strcpy_s

struct_copy.c
#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
#include <string.h>

typedef struct {
    int id;
    char name[20];
} Employee;

int main() {
    Employee emp;
    char src[] = "John Doe";

    // Safe copy into structure member
    errno_t result = strcpy_s(emp.name, sizeof(emp.name), src);

    if (result == 0) {
        emp.id = 1001;
        printf("Employee %d: %s\n", emp.id, emp.name);
    } else {
        printf("Failed to set employee name\n");
    }

    return 0;
}

此代码使用 strcpy_s 安全地将字符串复制到结构成员中。目标大小指定为结构字符数组的大小。这可以防止在处理固定大小的结构成员时发生缓冲区溢出。该示例显示了字符串操作的正确错误处理。这种模式对于安全地初始化结构字符串字段很有用。

将 strcpy_s 与字符串连接结合使用

此示例显示了如何结合使用 strcpy_sstrcat_s 来安全地构建字符串。

concat_copy.c
#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
#include <string.h>

int main() {
    char part1[] = "Hello";
    char part2[] = " World!";
    char buffer[20];

    // Safe initial copy
    errno_t result = strcpy_s(buffer, sizeof(buffer), part1);

    if (result != 0) {
        printf("Initial copy failed\n");
        return 1;
    }

    // Safe concatenation
    result = strcat_s(buffer, sizeof(buffer), part2);

    if (result == 0) {
        printf("Combined string: %s\n", buffer);
    } else {
        printf("Concatenation failed\n");
    }

    return 0;
}

此示例演示了如何使用 strcpy_s 进行初始复制,并使用 strcat_s 进行连接,从而安全地构建字符串。这两个函数都执行边界检查以防止缓冲区溢出。程序检查每个操作的返回值以处理错误。这种方法比在没有大小检查的情况下使用 strcpystrcat 更安全。在组合字符串操作时,请始终验证缓冲区大小。

使用 strcpy_s 的最佳实践

来源

C strcpy_s 文档

本教程探讨了 strcpy_s 函数,演示了其在安全字符串操作方面相对于 strcpy 的优势。虽然并非普遍可用,但它为现代 C 编程提供了重要的安全功能。在 C 中处理字符串时,请始终考虑安全性。

作者

我叫 Jan Bodnar,是一名敬业的程序员,对编码充满热情。自 2007 年以来,我通过 1,400 多篇文章和 8 本电子书分享我的专业知识。凭借十多年的教学经验,我努力使编程变得易于理解且引人入胜。

列表 C 标准库