strcat连接顺序会影响结果吗?

99ANYc3cd6
预计阅读时长 15 分钟
位置: 首页 C语言 正文

strcat 的执行顺序可以概括为 “先复制,后追加”

c语言strcat顺序
(图片来源网络,侵删)

它首先会找到目标字符串的末尾('\0'),然后从该位置开始,将源字符串的内容(包括其结尾的 '\0'依次复制到目标字符串的末尾。


详细执行步骤

假设我们有以下代码:

#include <stdio.h>
#include <string.h>
int main() {
    char dest[20] = "Hello, "; // 目标字符串
    char src[] = "World!";     // 源字符串
    printf("调用 strcat 前:\n");
    printf("dest = \"%s\"\n", dest);
    printf("src  = \"%s\"\n", src);
    // 调用 strcat 函数
    strcat(dest, src);
    printf("\n调用 strcat 后:\n");
    printf("dest = \"%s\"\n", dest);
    return 0;
}

strcat(dest, src) 的具体执行顺序如下:

步骤 1:定位目标字符串的末尾

函数首先会从 dest 字符串的第一个字符开始,向后查找,直到找到字符串的结束标记 '\0'

c语言strcat顺序
(图片来源网络,侵删)
  • dest 的初始内容是:'H', 'e', 'l', 'l', 'o', ',', ' ', '\0'
  • 函数找到 '\0' 的位置,在这个例子中,'\0' 位于索引 7(如果从0开始计数)。
  • 这个位置就是新的写入起点

步骤 2:从源字符串读取并复制到目标字符串

函数开始从 src 字符串的第一个字符读取,并将其逐个复制到 dest 字符串从 '\0' 位置开始的地方。

  1. 读取 src 的第一个字符 'W',将其写入 dest 的索引 7 位置。
    • dest 变为:'H', 'e', 'l', 'l', 'o', ',', ' ', 'W'
  2. 读取 src 的第二个字符 'o',将其写入 dest 的索引 8 位置。
    • dest 变为:'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o'
  3. ...这个过程持续进行...
  4. 读取 src 的最后一个字符 ,将其写入 dest 的某个位置(比如索引 11)。
    • dest 变为:'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!'
  5. 读取 src 的结束标记 '\0',将其写入 dest 的下一个位置(索引 12)。
    • dest 最终变为:'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!', '\0'

步骤 3:函数返回

strcat 函数执行完毕,并返回 dest 字符串的起始地址(即指向 dest[0] 的指针),虽然我们可以接收这个返回值,但在大多数情况下,我们都会忽略它,因为我们知道操作是直接在 dest 上进行的。

dest 的内容就变成了 "Hello, World!"


图示说明

让我们用图来更直观地展示这个过程。

c语言strcat顺序
(图片来源网络,侵删)

初始状态:

内存地址:  100   101   102   103   104   105   106   107   108   ...
dest:      'H'   'e'   'l'   'l'   'o'   ','   ' '   '\0'   ?    ...
src:      'W'   'o'   'r'   'l'   'd'   '!'   '\0'

步骤 1: 定位 dest 的末尾 ('\0')

函数发现 dest'\0' 在地址 106。

步骤 2: 开始追加 src 的内容

内存地址:  100   101   102   103   104   105   106   107   108   109   110   111   112   ...
dest:      'H'   'e'   'l'   'l'   'o'   ','   ' '   'W'   'o'   'r'   'l'   'd'   '!'   '\0'
src:      'W'   'o'   'r'   'l'   'd'   '!'   '\0'
  • src'W' (地址 100) -> 复制到 dest 的地址 107
  • src'o' (地址 101) -> 复制到 dest 的地址 108
  • src 的 (地址 105) -> 复制到 dest 的地址 111
  • src'\0' (地址 106) -> 复制到 dest 的地址 112

最终状态:

dest 指向一个完整的字符串 "Hello, World!",而 src 保持不变。


重要注意事项(陷阱)

  1. 目标缓冲区必须足够大 这是最重要的一点。strcat 不会检查目标缓冲区 dest 是否有足够的空间来容纳源字符串 srcdest 的大小不够,就会发生缓冲区溢出,这会覆盖 dest 之后的内存数据,导致程序崩溃、数据损坏或严重的安全漏洞(如被黑客利用)。

    错误示例:

    char dest[6] = "Hello"; // 只有6字节空间,最后一个给 '\0'
    char src[] = "World!";   // 需要6字节空间(5个字符 + '\0')
    strcat(dest, src);      // 崩溃!dest 只有6字节,无法容纳 "Hello" + "World!"
  2. 目标字符串必须以 '\0' dest 没有正确的 '\0' strcat 函数将无法找到字符串的末尾,它会一直向后读取内存,直到偶然遇到一个值为 0 的字节,这同样会导致越界访问和未定义行为。

  3. 源字符串不会被修改 strcat 是一个只读操作,它只读取 src 的内容,不会改变 src 的任何内容。

更安全的替代方案

为了防止缓冲区溢出,C 标准库提供了更安全的版本 strncat

  • strncat(dest, src, n): 它最多从 src 中复制 n 个字符到 dest 的末尾。
  • 关键点strncat 保证目标字符串 dest 总是以 '\0' 即使 src 的长度小于 n,它也会在复制完 src 后添加 '\0'src 的长度大于或等于 n,它只会复制 n 个字符,然后强制在末尾添加一个 '\0'

使用 strncat 的安全示例:

#include <stdio.h>
#include <string.h>
int main() {
    char dest[20] = "Hello, ";
    char src[] = "World!";
    // 安全地追加,最多追加 sizeof(dest) - 1 - strlen(dest) 个字符
    // sizeof(dest) - 1 是为了留出 '\0' 的位置
    // strlen(dest) 是 "Hello, " 的长度
    // 所以最多可以追加 20 - 1 - 7 = 12 个字符,足以容纳 "World!"
    strncat(dest, src, sizeof(dest) - strlen(dest) - 1);
    printf("dest = \"%s\"\n", dest); // 输出: dest = "Hello, World!"
    return 0;
}
特性 描述
执行顺序 先找 dest 的末尾 '\0',然后从该位置开始,将 src 的内容(包括 '\0')复制过去。
关键操作 复制,它不是简单地拼接两个字符串,而是将一个字符串的内容复制到另一个字符串的末尾。
安全性 不安全,容易导致缓冲区溢出。
使用前提 dest 必须有足够大的空间,并且必须以 '\0'
推荐替代 使用 strncat 并正确计算要复制的最大字符数,以防止缓冲区溢出。
-- 展开阅读全文 --
头像
dede数据表结构具体包含哪些字段?
« 上一篇 04-04
ARM C语言中如何高效操作bit位?
下一篇 » 04-04

相关文章

取消
微信二维码
支付宝二维码