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_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
值不暴露行将发生的缓冲区溢出。- 同所有边界检查函数,
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> 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
引用
- C11 standard (ISO/IEC 9899:2011):
- 7.24.2.4 The strncpy function (p: 363-364)
- K.3.7.1.4 The strncpy_s function (p: 616-617)
- C99 standard (ISO/IEC 9899:1999):
- 7.21.2.4 The strncpy function (p: 326-327)
- C89/C90 standard (ISO/IEC 9899:1990):
- 4.11.2.4 The strncpy function
参阅
(C11) |
复制一个字符串给另一个 (函数) |
(C11) |
将一个缓冲区复制到另一个 (函数) |
(动态内存 TR) |
分配字符串副本,至多到指定的大小 (函数) |