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
可用。
目录 |
[edit] 参数
dest | - | 指向要复制到的字符数组的指针 |
src | - | 指向要从中复制的字符数组的指针 |
count | - | 要复制的最大字符数 |
destsz | - | 目标缓冲区的大小 |
[edit] 返回值
1) 返回
dest
的副本2) 成功时返回零,错误时返回非零值。此外,在错误时,将零写入 dest[0] (除非
dest
是空指针或 destsz
为零或大于 RSIZE_MAX),并且可能会用未指定的值覆盖目标数组的其余部分。[edit] 注解
正如 C11 之后 DR 468 修正的那样,与 strcpy_s 不同,strncpy_s
仅在发生错误时才允许覆盖目标数组的剩余部分。
与 strncpy
不同,strncpy_s
不会用零填充目标数组。当将现有代码转换为边界检查版本时,这是一个常见的错误来源。
虽然截断以适应目标缓冲区是一种安全风险,因此对于 strncpy_s
来说是运行时约束违规,但可以通过指定 count
等于目标数组的大小减一来获得截断行为:它将复制前 count
个字节并始终附加空终止符:strncpy_s(dst, sizeof dst, src, (sizeof dst)-1);
[edit] 示例
运行此代码
#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
[edit] 参考文献
- 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 函数
[edit] 参见
(C11) |
将一个字符串复制到另一个字符串 (函数) |
(C11) |
将一个缓冲区复制到另一个缓冲区 (函数) |
(动态内存 TR) |
分配一个字符串的副本,最多指定大小 (函数) |
C++ 文档,关于 strncpy
|