源字符串长于目标数组的 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));
我试着思考如何实现这个功能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));