strncpy, strncpy_s
来自 cppreference.cn
| 定义于头文件 <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),并且可能会用未指定的值覆盖目标数组的其余部分。[编辑] 注意
根据 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++ 文档 适用于 strncpy
| |