源字符串长于目标数组的 strncpy 问题

Problem on strncpy with source string longer than destination array

我试着思考如何实现这个功能strncpy,但我遇到了这个问题。

    char src[] = "123456789A";
    char dest[10];
    int n = 10;
    printf("strncpy:%s\n", strncpy(dest, src, n));

输出

strncpy:123456789A123456789A

发生了什么事?

数组 dest 不包含字符串,因为没有足够的 space 来容纳复制的源字符串的终止零 '[=15=]'

所以要输出数组使用下面的语句

printf("strncpy: %*.*s\n", n, n, strncpy(dest, src, n));

否则你必须写成类似下面的东西

strncpy( dest, src, n )[sizeof( dest ) - 1] = '[=11=]';

printf("strncpy: %s\n", dest );

在这种情况下,目标数组将不会包含将被零字符覆盖的源字符串的最后一个字符。

如果你想复制的字符少于目标数组的大小,那么复制后要做什么取决于你的意图。如果您只想覆盖已存储在目标数组中的字符串的一部分,则无需执行任何其他操作。否则将位置 n 处的字符设置为零字符。

这是一个演示程序。

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

int main(void) 
{
    char src[] = "123456789A";
    char dest[10] = "543216789";

    size_t n = 5;

    strncpy( dest, src, n );

    printf("strncpy: %s\n", dest );

    strncpy( dest, "Hello", n )[n] = '[=12=]';

    printf("strncpy: %s\n", dest );

    return 0;
}

它的输出是

strncpy: 123456789
strncpy: Hello

快速回答:strncpy 不是你的朋友!

strncpy 不是 更安全的 版本的 strcpy,它将最多复制 n 来自 src 的字符,如果 src 更短,将用空字节填充目标,总共 n 个字符。

如果源字符串有 n 个或更多字符,目标数组将 不以 null 终止 并且传递给 printf("%s", 将有 未定义的行为printf 将在 dest 结束后继续从内存中读取和打印字节,直到找到空字节或直到此未定义的行为导致其他不可预测的副作用。 ..

strncpy的语义违反直觉且容易出错,请避免使用此函数。详见本文:https://randomascii.wordpress.com/2013/04/03/stop-using-strncpy-already/

正如其他人所说,如果目标大小与字符串长度相同,strncpy 将不会包含终止空值。为了给你一个实际的答案,我通常只是使用 sizeof 从目标大小中减去一个以获得目标大小,包括终止符的 space:

char src[] = "123456789A";
char dest[10];
printf("strncpy:%s\n", strncpy(dest, src, sizeof(dest) - 1));

它给出了 "strncpy:123456789" 的输出,它是一个缺少您想要的字符,但至少是定义的行为,并且让您知道目标缓冲区不够大,无法包含空终止符。因此,为您提供所需结果的最终代码将是:

char src[] = "123456789A";
char dest[11];
printf("strncpy:%s\n", strncpy(dest, src, sizeof(dest) - 1));