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
指向的以 null 结尾的字节字符串的末尾,如果找到空字符,则停止。字符 src[0] 替换 dest
末尾的 null 终止符。终止 null 字符始终追加在末尾(因此函数可能写入的最大字节数为 count+1)。 如果目标数组没有足够的空间容纳
dest
和 src
的前 count
个字符以及终止 null 字符的内容,则行为未定义。如果源对象和目标对象重叠,则行为未定义。如果 dest
不是指向以 null 结尾的字节字符串的指针,或者 src
不是指向字符数组的指针,则行为未定义。2) 与 (1) 相同,除了此函数可能会覆盖目标数组的剩余部分(从最后一个写入到
destsz
的字节开始),并且以下错误将在运行时检测到,并调用当前安装的 约束处理程序 函数-
src
或dest
为空指针 -
destsz
或count
为零或大于 RSIZE_MAX dest
的前destsz
个字节中没有空字符- 将发生截断:
count
或src
的长度(以较小的为准)超过了dest
的 null 终止符和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 | - | 指向要追加的以 null 结尾的字节字符串的指针 |
src | - | 指向要从中复制的字符数组的指针 |
count | - | 要复制的最大字符数 |
destsz | - | 目标缓冲区的大小 |
[编辑] 返回值
1) 返回
dest
的副本2) 成功返回零,错误返回非零。此外,在发生错误时,将零写入 dest[0](除非
dest
为空指针或 destsz
为零或大于 RSIZE_MAX)。[编辑] 注释
由于 strncat
需要在每次调用时都寻找 dest
的末尾,因此使用 strncat
将许多字符串连接成一个字符串效率很低。
虽然截断以适应目标缓冲区是一种安全风险,因此对于 strncat_s
来说是运行时约束违反,但可以通过将 count
指定为目标数组的大小减一来获得截断行为:它将复制前 count
个字节,并像往常一样追加 null 终止符: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 is 0, s1 holds "goodbye\0" printf("s1 = %s, r1 = %d\n", s1, r1); char s2[6] = "hello"; int r2 = strncat_s(s2, 6, "", 1); // r2 is 0, s2 holds "hello\0" printf("s2 = %s, r2 = %d\n", s2, r2); char s3[6] = "hello"; int r3 = strncat_s(s3, 6, "X", 2); // r3 is non-zero, s3 holds "\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); // r4 is 0, s4 holds "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
[编辑] 参考文献
- C23 标准 (ISO/IEC 9899:2024)
- 7.26.3.2 strncat 函数 (p: 379)
- K.3.7.2.2 strncat_s 函数 (p: TBD)
- C17 标准 (ISO/IEC 9899:2018)
- 7.24.3.2 strncat 函数 (p: 265-266)
- K.3.7.2.2 strncat_s 函数 (p: 449-450)
- C11 标准 (ISO/IEC 9899:2011)
- 7.24.3.2 strncat 函数 (p: 364-365)
- K.3.7.2.2 strncat_s 函数 (p: 618-620)
- C99 标准 (ISO/IEC 9899:1999)
- 7.21.3.2 strncat 函数 (p: 327-328)
- C89/C90 标准 (ISO/IEC 9899:1990)
- 4.11.3.2 strncat 函数
[编辑] 参见
(C11) |
连接两个字符串 (函数) |
(C11) |
将一个字符串复制到另一个字符串 (函数) |
(C23) |
将一个缓冲区复制到另一个缓冲区,在指定的定界符后停止 (函数) |
C++ 文档 for strncat
|