strncat, strncat_s
来自cppreference.com
在标头 <string.h> 定义
|
||
(1) | ||
char *strncat( char *dest, const char *src, size_t count ); |
(C99 前) | |
char *strncat( char *restrict dest, const char *restrict src, size_t count ); |
(C99 起) | |
errno_t strncat_s(char *restrict dest, rsize_t destsz, const char *restrict src, rsize_t count); |
(2) | (C11 起) |
1) 后附来自
src
所指向的字符数组的至多 count
个字符,到 dest
所指向的空终止字节字符串的末尾,若找到空字符则停止。字符 src[0] 替换位于 dest
末尾的空终止符。始终后附终止空字符到末尾(故函数可写入的最大字节数是 count+1 )。 若目标数组没有对于
dest
和 src
的首 count
个字符加上终止空字符的足够空间,则行为未定义。若源与目标对象重叠,则行为未定义。若 dest
不是指向空终止字节字符串的指针,或 src
不是指向字符数组的指针,则行为未定义。2) 同 (1) ,除了函数可以可用未指定值破坏目标数组的剩余部分(从最后写入字符到
destsz
),以及在运行时检测下列错误,并调用当前安装的约束处理函数:
-
src
或dest
为空指针 -
destsz
或count
为零或大于 RSIZE_MAX -
dest
的首destsz
个字节中无空字符 - 会出现截断:
count
与src
长度的较小者,会超出dest
的空终止符和destsz
之间的可用空间。 - 源与目标字符串之间会出现重叠
-
若
dest
所指向的字符数组大小 < strnlen(dest,destsz)+strnlen(src,count)+1 < destsz
则行为未定义;换言之, destsz
的错误值不暴露行将发生的缓冲区溢出。若 src
所指向的字符数组大小 < strnlen(src,count) < destsz
;换言之, count
的错误值不暴露行将发生的缓冲区溢出。
- 同所有边界检查函数,
strncat_s
仅若实现定义了 __STDC_LIB_EXT1__ ,且用户在包含string.h
前定义 __STDC_WANT_LIB_EXT1__ 为整数常量 1 才保证可用。
参数
dest | - | 指向要后附到的空终止字节字符串的指针 |
src | - | 指向作为复制来源的字符数组的指针 |
count | - | 要复制的最大字符数 |
destsz | - | 目标缓冲区的大小 |
返回值
1) 返回
dest
的副本。2) 成功时返回零。错误时返回非零。错误时,亦写入零到 dest[0] (除非
dest
为空指针,或 destsz
为零或大于 RSIZE_MAX )。注解
因为 strncat
需要在每次调用时找到 dest
的结尾,故用 strncat
将多个字符串连接成一体是低效的。
尽管截断以适应目标缓冲区是安全风险,从而是 strncat_s
的运行时制约违规,还是可以通过指定 count
等于目标数组大小减一获取截断行为:这将一如往常地复制首 count
个字节并后附空终止符: strncat_s(dst, sizeof dst, src, (sizeof dst)-strnlen_s(dst, sizeof dst)-1); 。
示例
运行此代码
#define __STDC_WANT_LIB_EXT1__ 1 #include <string.h> #include <stdio.h> #include <stdlib.h> int main(void) { char str[50] = "Hello "; char str2[50] = "World!"; strcat(str, str2); strncat(str, " Goodbye World!", 3); puts(str); #ifdef __STDC_LIB_EXT1__ set_constraint_handler_s(ignore_handler_s); char s1[100] = "good"; char s5[1000] = "bye"; int r1 = strncat_s(s1, 100, s5, 1000); // r1 为 0 , s1 保有 "goodbye\0" printf("s1 = %s, r1 = %d\n", s1, r1); char s2[6] = "hello"; int r2 = strncat_s(s2, 6, "", 1); // r2 为 0 , s2 保有 "hello\0" printf("s2 = %s, r2 = %d\n", s2, r2); char s3[6] = "hello"; int r3 = strncat_s(s3, 6, "X", 2); // r3 非零, s3 保有 "\0" printf("s3 = %s, r3 = %d\n", s3, r3); // the strncat_s truncation idiom: char s4[7] = "abc"; int r4 = strncat_s(s4, 7, "defghijklmn", 3); // r 为 0 , s4 保有 "abcdef\0" printf("s4 = %s, r4 = %d\n", s4, r4); #endif }
可能的输出:
Hello World! Go s1 = goodbye, r1 = 0 s2 = hello, r2 = 0 s3 = , r3 = 22 s4 = abcdef, r4 = 0
引用
- C11 标准(ISO/IEC 9899:2011):
- 7.24.3.2 The strncat function (第 364-365 页)
- K.3.7.2.2 The strncat_s function (第 618-620 页)
- C99 标准(ISO/IEC 9899:1999):
- 7.21.3.2 The strncat function (第 327-328 页)
- C89/C90 标准(ISO/IEC 9899:1990):
- 4.11.3.2 The strncat function
参阅
(C11) |
连接两个字符串 (函数) |
(C11) |
复制一个字符串给另一个 (函数) |