strncpy, strncpy_s
来自cppreference.com
<tbody>
</tbody>
<tbody class="t-dcl-rev t-dcl-rev-num ">
</tbody><tbody>
</tbody>
| 在标头 <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,仅若错误发生才被允许破坏目标数组的剩余部分。
不同于 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) |
分配字符串副本,至多到指定的大小 (函数) |
strncpy 的 C++ 文档
| |