strcat函数如何实现字符串连接?

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

strcat 是 "string concatenate"(字符串连接)的缩写,它的作用是将源字符串(source string)追加到目标字符串(destination string)的末尾,并在连接后的新字符串末尾添加一个空字符 \0

标准库 strcat 的行为回顾

在开始实现之前,我们先回顾一下标准库 strcat 的关键点:

  1. 函数原型:
    char *strcat(char *dest, const char *src);
  2. 参数:
    • dest: 目标字符串的缓冲区。这个缓冲区必须足够大,能够容纳 destsrc 两个字符串的内容,以及一个额外的 \0 字符,如果空间不足,会导致缓冲区溢出,这是非常危险的。
    • src: 源字符串,这个字符串通常是常量(const),意味着 strcat 函数不会修改它。
  3. 返回值:
    • 返回一个指向 dest 缓冲区首地址的指针。
  4. 工作原理:
    • strcat 会找到 dest 字符串的末尾(即第一个 \0 的位置)。
    • 它从 src 字符串的第一个字符开始,逐个字符地拷贝到 dest 字符串的末尾。
    • 它会在拷贝完 src 的所有字符后,在 dest 的末尾添加一个 \0

strcat 的 C 语言实现

下面我们将分步实现一个自己的 my_strcat 函数。

实现思路

  1. 找到目标字符串的末尾:创建一个指针,让它指向 dest 的起始位置,然后不断向后移动,直到遇到 \0 字符。
  2. 进行拷贝:这个指针就指向了 dest 的末尾,我们再用一个指针指向 src 的起始位置,然后将 src 的内容逐个字符地拷贝到 dest 的末尾位置。
  3. 添加终止符:当 src 的所有字符(包括它末尾的 \0)都被拷贝过去后,dest 就自动拥有了正确的终止符,返回 dest 的起始地址。

代码实现

#include <stdio.h>
/**
 * @brief 自定义字符串连接函数
 * @param dest 目标字符串缓冲区,必须足够大
 * @param src  源字符串
 * @return 返回连接后的目标字符串的起始地址
 */
char *my_strcat(char *dest, const char *src) {
    char *ptr = dest; // 保存 dest 的起始地址,用于最后返回
    // 1. 移动指针到 dest 字符串的末尾
    // 循环在 *dest 不为 '\0' 时继续
    while (*dest != '\0') {
        dest++;
    }
    // 循环结束后,dest 指针指向了 dest 字符串末尾的 '\0' 的位置
    // 2. 将 src 字符串的内容拷贝到 dest 的末尾
    // 循环在 *src 不为 '\0' 时继续
    while (*src != '\0') {
        *dest = *src; // 拷贝字符
        dest++;       // 移动 dest 指针到下一个位置
        src++;        // 移动 src 指针到下一个位置
    }
    // 3. 在连接后的字符串末尾添加 '\0'
    // 上面的循环在 *src 为 '\0' 时停止,*dest 已经被赋值为 '\0'
    // 所以这一步是隐含的,但显式写上更清晰
    *dest = '\0';
    // 4. 返回连接后的字符串起始地址
    return ptr;
}
// --- 测试代码 ---
int main() {
    // 定义一个足够大的缓冲区
    char str1[50] = "Hello, "; // 注意:要留出足够的空间
    char str2[] = "world!";
    printf("连接前 str1: %s\n", str1);
    printf("连接前 str2: %s\n", str2);
    // 调用自定义的 my_strcat 函数
    // 将 str2 连接到 str1 的末尾
    my_strcat(str1, str2);
    printf("连接后 str1: %s\n", str1);
    // 另一个测试用例
    char path[100] = "/usr/local/";
    char file[] = "bin/program";
    my_strcat(path, file);
    printf("构建的完整路径: %s\n", path);
    return 0;
}

代码解析

  1. char *ptr = dest;:我们创建了一个临时指针 ptr 来保存 dest 的原始地址,因为后续的 dest 指针会移动到字符串末尾,所以我们需要 ptr 来记住起点,以便最后返回。
  2. while (*dest != '\0') { dest++; }:这是第一个 while 循环,它的唯一目的就是找到 dest 字符串的结尾,当 *destdest 当前指向的字符)不是空字符 \0 时,指针 dest 就向后移动一位。
  3. while (*src != '\0') { ... }:这是第二个 while 循环,负责实际的拷贝工作。dest 指针正停在 dest 原字符串末尾的 \0 位置,循环将 src 指向的字符逐个赋值给 dest 指向的位置,然后两个指针同时向后移动。
  4. *dest = '\0';:当 src 字符串被完全拷贝后,src 指针会指向 src 字符串末尾的 \0,循环结束,*dest 的值就是 *src 的值,也就是 \0,所以这行代码虽然是显式添加,但在逻辑上已经完成了。
  5. return ptr;:返回最初保存的 dest 的起始地址,这是标准 strcat 的行为。

安全性考虑与 strncat

标准 strcat 的主要问题是它不检查目标缓冲区的大小,非常容易导致缓冲区溢出,为了解决这个问题,C 标准库提供了 strncat

strncat 增加了一个参数 n,用来限制最多可以拷贝的字符数。

strncat 的原型

char *strncat(char *dest, const char *src, size_t n);

strncat 的实现逻辑

strncat 的实现与 strcat 非常相似,只是在第二个拷贝循环中增加了一个计数器 n

char *my_strncat(char *dest, const char *src, size_t n) {
    char *ptr = dest;
    // 1. 同样,先找到 dest 的末尾
    while (*dest != '\0') {
        dest++;
    }
    // 2. 拷贝,但最多只拷贝 n 个字符
    // src 比 n 短,则在 src 结束时停止
    // src 比 n 长,则在拷贝 n 个字符后停止
    while (n > 0 && *src != '\0') {
        *dest = *src;
        dest++;
        src++;
        n--; // 每次拷贝后,n 减 1
    }
    // 3. 确保结果字符串总是以 '\0' 
    *dest = '\0';
    return ptr;
}

strncatstrcat 更安全,因为它可以防止拷贝超过目标缓冲区容量的数据,但在使用 strncat 时,仍需确保目标缓冲区至少有 strlen(dest) + n + 1 的空间。

特性 strcat my_strcat (自定义实现) strncat (安全版)
功能 字符串连接 自定义字符串连接 安全的字符串连接
原型 char *strcat(char *dest, const char *src) char *my_strcat(char *dest, const char *src) char *strncat(char *dest, const char *src, size_t n)
安全性 不安全,易发生缓冲区溢出 不安全,与标准版一样 相对安全,通过 n 参数限制拷贝长度
核心逻辑 找到 dest 末尾
拷贝 src 到末尾
找到 dest 末尾
拷贝 src 到末尾
找到 dest 末尾
最多拷贝 n 个字符
返回值 dest 的起始地址 dest 的起始地址 dest 的起始地址

理解 strcat 的实现原理是 C 语言指针操作和字符串处理的一个非常好的练习,在实际开发中,强烈推荐使用 strncat 或更安全的、能自动计算长度的 strlcat(在 BSD 系统中可用),以避免缓冲区溢出的安全风险。

-- 展开阅读全文 --
头像
kdtree c语言库
« 上一篇 今天
织梦栏目生成html,如何操作实现?
下一篇 » 今天
取消
微信二维码
支付宝二维码

目录[+]