strncpy, strncpy_s
来自 cppreference.com
在头文件 <string.h> 中定义 |
||
(1) | ||
char *strncpy( char *dest, const char *src, size_t count ); |
(直到 C99) | |
char *strncpy( char *restrict dest, const char *restrict src, size_t count ); |
(从 C99 开始) | |
errno_t strncpy_s( char *restrict dest, rsize_t destsz, const char *restrict src, rsize_t count ); |
(2) | (从 C11 开始) |
1) 将
src
指向的字符数组中的最多 count
个字符(包括终止空字符,但不包括任何跟随空字符的字符)复制到 dest
指向的字符数组中。 如果在复制整个数组
src
之前到达 count
,则结果字符数组不会以空字符结尾。 如果在从
src
复制终止空字符之后,未达到 count
,则会向 dest
写入额外的空字符,直到总共写入 count
个字符。 如果字符数组重叠,或者
dest
或 src
不是指向字符数组的指针(包括 dest
或 src
是空指针),或者 dest
指向的数组的大小小于 count
,或者 src
指向的数组的大小小于 count
且不包含空字符,则行为未定义。2) 与 (1) 相同,但该函数不会继续向目标数组写入零来填充至
count
,它在写入终止空字符后停止(如果源中没有空字符,它会在 dest[count] 处写入一个,然后停止)。此外,以下错误在运行时被检测到并调用当前已安装的 约束处理程序 函数-
src
或dest
是空指针 -
destsz
为零或大于 RSIZE_MAX -
count
大于 RSIZE_MAX -
count
大于或等于destsz
,但destsz
小于或等于 strnlen_s(src, count),换句话说,将发生截断 - 源字符串和目标字符串之间会发生重叠
-
如果
dest
指向的字符数组的大小 < strnlen_s(src, destsz) <= destsz
,则行为未定义;换句话说,destsz
的错误值不会暴露即将发生的缓冲区溢出。如果 src
指向的字符数组的大小 < strnlen_s(src, count) < destsz
,则行为未定义;换句话说,count
的错误值不会暴露即将发生的缓冲区溢出。- 与所有边界检查函数一样,只有在实现定义了 __STDC_LIB_EXT1__ 且用户在包含 <string.h> 之前将 __STDC_WANT_LIB_EXT1__ 定义为整型常量 1 时,才能保证
strncpy_s
可用。
内容 |
[编辑] 参数
dest | - | 指向要复制到的字符数组的指针 |
src | - | 指向要从中复制的字符数组的指针 |
count | - | 要复制的最大字符数 |
destsz | - | 目标缓冲区的大小 |
[编辑] 返回值
1) 返回
dest
的副本2) 成功返回零,错误返回非零。此外,如果发生错误,会向 dest[0] 写入零(除非
dest
是空指针或 destsz
为零或大于 RSIZE_MAX),并且可能会用未指定的 value 覆盖目标数组的其余部分。[编辑] 注意
正如 C11 后的 DR 468 所修正的,strncpy_s
与 strcpy_s 不同,只有在发生错误时才允许覆盖目标数组的其余部分。
与 strncpy
不同,strncpy_s
不会用零填充目标数组。这是将现有代码转换为边界检查版本时常见的错误来源。
尽管截断以适合目标缓冲区是一个安全风险,因此对于 strncpy_s
来说是一个运行时约束违规,但可以通过将 count
指定为目标数组大小减一来获得截断行为:它将复制前 count
个字节并像往常一样追加空终止符:strncpy_s(dst, sizeof dst, src, (sizeof dst)-1);
[编辑] 示例
运行此代码
#define __STDC_WANT_LIB_EXT1__ 1 #include <string.h> #include <stdio.h> #include <stdlib.h> #include <errno.h> int main(void) { char src[] = "hi"; char dest[6] = "abcdef"; // no null terminator strncpy(dest, src, 5); // writes five characters 'h', 'i', '\0', '\0', '\0' to dest printf("strncpy(dest, src, 5) to a 6-byte dest gives : "); for (size_t n = 0; n < sizeof dest; ++n) { char c = dest[n]; c ? printf("'%c' ", c) : printf("'\\0' "); } printf("\nstrncpy(dest2, src, 2) to a 2-byte dst gives : "); char dest2[2]; strncpy(dest2, src, 2); // truncation: writes two characters 'h', 'i', to dest2 for (size_t n = 0; n < sizeof dest2; ++n) { char c = dest2[n]; c ? printf("'%c' ", c) : printf("'\\0' "); } printf("\n"); #ifdef __STDC_LIB_EXT1__ set_constraint_handler_s(ignore_handler_s); char dst1[6], src1[100] = "hello"; errno_t r1 = strncpy_s(dst1, 6, src1, 100); // writes 0 to r1, 6 characters to dst1 printf("dst1 = \"%s\", r1 = %d\n", dst1,r1); // 'h','e','l','l','o','\0' to dst1 char dst2[5], src2[7] = {'g','o','o','d','b','y','e'}; errno_t r2 = strncpy_s(dst2, 5, src2, 7); // copy overflows the destination array printf("dst2 = \"%s\", r2 = %d\n", dst2,r2); // writes nonzero to r2,'\0' to dst2[0] char dst3[5]; errno_t r3 = strncpy_s(dst3, 5, src2, 4); // writes 0 to r3, 5 characters to dst3 printf("dst3 = \"%s\", r3 = %d\n", dst3,r3); // 'g', 'o', 'o', 'd', '\0' to dst3 #endif }
可能的输出
strncpy(dest, src, 5) to a 6-byte dst gives : 'h' 'i' '\0' '\0' '\0' 'f' strncpy(dest2, src, 2) to a 2-byte dst gives : 'h' 'i' dst1 = "hello", r1 = 0 dst2 = "", r2 = 22 dst3 = "good", r3 = 0
[编辑] 参考文献
- C17 标准(ISO/IEC 9899:2018)
- 7.24.2.4 strncpy 函数(p: 265)
- K.3.7.1.4 strncpy_s 函数(p: 447-448)
- C11 标准(ISO/IEC 9899:2011)
- 7.24.2.4 strncpy 函数(p: 363-364)
- K.3.7.1.4 strncpy_s 函数(p: 616-617)
- C99 标准(ISO/IEC 9899:1999)
- 7.21.2.4 strncpy 函数(p: 326-327)
- C89/C90 标准(ISO/IEC 9899:1990)
- 4.11.2.4 strncpy 函数
[编辑] 另请参阅
(C11) |
将一个字符串复制到另一个字符串 (函数) |
(C11) |
将一个缓冲区复制到另一个缓冲区 (函数) |
(动态内存 TR) |
分配一个字符串副本,最多指定大小 (函数) |
C++ 文档 for strncpy
|