strncpy, strncpy_s
|
在标头
<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_MAXcount大于 RSIZE_MAXcount大于或等于destsz,但destsz小于或等于 strnlen_s(src, count),换言之,会出现截断- 源和目标字符串间会出现重叠
若
dest 所指的字符数组大小 < strnlen_s(src, destsz) <= destsz 则行为未定义;换言之,错误的 destsz 值不暴露行将发生的缓冲区溢出。若 src 所指的字符数组大小 < strnlen_s(src, count) < destsz 则行为未定义;换言之,错误的 count 值不暴露行将发生的缓冲区溢出。- 同所有边界检查函数,
strncpy_s,仅若实现定义 __STDC_LIB_EXT1__ 且用户在包含 <string.h> 前定义 __STDC_WANT_LIB_EXT1__ 为整数常量 1 才保证可用。
参数
| 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"; // 无空字符 strncpy(dest, src, 5); // 写入五个字符 'h', 'i', '\0', '\0', '\0' 到 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); // 截断:写入二个字符 'h', 'i', 到 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"; int r1 = strncpy_s(dst1, 6, src1, 100); // 写入 0 到 r1,6 个字符到 dst1 printf("dst1 = \"%s\", r1 = %d\n", dst1,r1); // 'h','e','l','l','o','\0' 到 dst1 char dst2[5], src2[7] = {'g','o','o','d','b','y','e'}; int r2 = strncpy_s(dst2, 5, src2, 7); // 复制溢出目标数组 printf("dst2 = \"%s\", r2 = %d\n", dst2,r2); // 写入非零到 r2,'\0' 到 dst2[0] char dst3[5]; int r3 = strncpy_s(dst3, 5, src2, 4); // 写入 0 到 r3,5 个字符到 dst3 printf("dst3 = \"%s\", r3 = %d\n", dst3,r3); // 'g', 'o', 'o', 'd', '\0' 到 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 The strncpy function (第 265 页)
-
- K.3.7.1.4 The strncpy_s function (第 447-448 页)
- C11 标准(ISO/IEC 9899:2011):
-
- 7.24.2.4 The strncpy function (第 363-364 页)
-
- K.3.7.1.4 The strncpy_s function (第 616-617 页)
- C99 标准(ISO/IEC 9899:1999):
-
- 7.21.2.4 The strncpy function (第 326-327 页)
- C89/C90 标准(ISO/IEC 9899:1990):
-
- 4.11.2.4 The strncpy function
参阅
|
(C11)
|
复制一个字符串给另一个 (函数) |
|
(C11)
|
将一个缓冲区复制到另一个 (函数) |
|
(动态内存 TR)
|
分配字符串副本,至多到指定的大小 (函数) |