ZetCode

C strncpy 函数

最后修改:2025 年 4 月 8 日

字符串操作在 C 编程中至关重要,而 strncpy 是安全复制字符串的关键函数。本教程将深入探讨 strncpy,包括其语法、用法和潜在的陷阱。我们将探讨实际示例,并讨论对关键应用程序更安全的替代方案。了解 strncpy 有助于防止缓冲区溢出,同时维护程序的安全性和可靠性。

什么是 strncpy?

strncpy 函数将源字符串中的最多 n 个字符复制到目标。它在 string.h 中声明,并接受三个参数:目标、源和要复制的最大字符数。与 strcpy 不同,strncpy 提供边界检查以防止缓冲区溢出。但是,如果源字符串的长度大于 n 个字符,它不保证空终止。

基本的 strncpy 用法

此示例演示了使用 strncpy 复制字符串。

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

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

    // Copy up to 14 characters
    strncpy(dest, src, 14);

    printf("Source: %s\n", src);
    printf("Destination: %s\n", dest);

    return 0;
}

在此,strncpysrc 中的最多 14 个字符复制到 dest。目标缓冲区必须足够大才能容纳复制的数据。与 strcpy 不同,如果源字符串过长,此版本可以防止缓冲区溢出。但是,如果源字符串的长度等于或大于指定的计数,它可能不会使目标空终止。

确保空终止

此示例显示了在使用 strncpy 时如何保证空终止。

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

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

    // Copy up to 9 characters and ensure null termination
    strncpy(dest, src, sizeof(dest) - 1);
    dest[sizeof(dest) - 1] = '\0';

    printf("Source: %s\n", src);
    printf("Destination: %s\n", dest);

    return 0;
}

此代码安全地复制字符串,同时确保空终止。我们复制的字符比目标大小少一个,然后显式添加空终止符。这是在使用 strncpy 处理固定大小缓冲区时的常见模式。请始终记住,如果源字符串的长度大于指定的计数,strncpy 不会自动进行空终止。

复制部分字符串

此示例演示了使用 strncpy 复制字符串的一部分。

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

int main() {
    char src[] = "Programming in C";
    char dest[10];

    // Copy first 5 characters of "Programming"
    strncpy(dest, src, 5);
    dest[5] = '\0'; // Ensure null termination

    printf("Source: %s\n", src);
    printf("First 5 characters: %s\n", dest);

    return 0;
}

在这里,我们只复制源字符串的前 5 个字符。复制后,我们显式添加一个空终止符以确保正确的字符串终止。当您需要子字符串或想限制复制数据的长度时,此技术非常有用。使用 strncpy 复制部分字符串时,请始终记住手动进行空终止。

比较 strncpy 和 strcpy

此示例强调了 strncpystrcpy 之间的区别。

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

int main() {
    char long_str[] = "This string is definitely too long";
    char small_buf[10];

    // Dangerous strcpy (potential buffer overflow)
    // strcpy(small_buf, long_str); // Would crash
    
    // Safer strncpy
    strncpy(small_buf, long_str, sizeof(small_buf) - 1);
    small_buf[sizeof(small_buf) - 1] = '\0';

    printf("Safe copy: %s\n", small_buf);
    return 0;
}

此示例演示了为什么 strncpystrcpy 更安全。注释掉的 strcpy 会导致缓冲区溢出。strncpy 版本将复制限制在缓冲区大小内,并确保空终止。在处理潜在的不可信输入或固定大小缓冲区时,请始终优先使用 strncpy 或类似的安全函数。

将 strncpy 与结构体数组一起使用

此示例显示了将 strncpy 与结构体数组一起使用。

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

#define MAX_NAME 20
#define NUM_STUDENTS 3

typedef struct {
    int id;
    char name[MAX_NAME];
} Student;

int main() {
    Student class[NUM_STUDENTS];
    const char *names[NUM_STUDENTS] = {"Alice", "Bob", "Charlie"};

    for (int i = 0; i < NUM_STUDENTS; i++) {
        class[i].id = i + 1;
        strncpy(class[i].name, names[i], MAX_NAME - 1);
        class[i].name[MAX_NAME - 1] = '\0';
    }

    printf("Student List:\n");
    for (int i = 0; i < NUM_STUDENTS; i++) {
        printf("%d: %s\n", class[i].id, class[i].name);
    }

    return 0;
}

此代码使用 strncpy 安全地将学生姓名复制到结构体数组中。每个姓名的长度限制为 MAX_NAME - 1 个字符,以便为空终止符留出空间。这是在结构体中使用固定大小的字符串字段时常见的模式。它可以在保持数据完整性的同时防止缓冲区溢出。

使用 strncpy 的最佳实践

来源

C strncpy 文档

本教程从基本用法到高级注意事项,都探讨了 strncpy 函数。虽然它比 strcpy 更安全,但正确使用 strncpy 需要注意空终止和缓冲区大小。

作者

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

列表 C 标准库