C语言实现的自定义strstr函数

引言

        strstr函数是一个内置函数,用于在一个字符串(haystack)中查找另一个子字符串(needle)。当找到子字符串时,它会返回该子字符串在主字符串中的起始地址。今天,我们将通过一个自定义实现的my_strstr函数来详细解析这一过程。

导图

代码举例

// 定义一个名为my_strstr的自定义函数,功能类似于C标准库中的strstr函数,用于在字符串p1中查找字符串p2
char* my_strstr(const char* p1, const char* p2) {
    // 使用assert断言确保输入的两个字符串指针都不指向空字符,即都不是空字符串
    assert(*p1 && *p2);

    // 初始化三个字符指针:s1,s2和stu,其中stu初始指向p1的首地址
    char* s1 = NULL;
    char* s2 = NULL;
    char* stu = (char*)p1;

    // 特殊情况:如果p2为空字符串(只包含结束符''),则返回p1的首地址
    if (*p2 == '') {
        return (char*)p1;
    }

    // 主循环,遍历字符串p1直到遇到结束符''
    while (*stu) {
        // 将s1和s2分别指向stu和p2的当前字符,开始新一轮的比较
        s1 = stu;
        s2 = (char*)p2;

        // 内部循环,逐个比较s1和s2指向的字符,如果相同则继续比较下一个字符
        // 直到遇到任意一个字符串的结束符''或者发现不相等的字符为止
        while (*s1 && *s2 && (*s1 == *s2)) { // ''的ASCII码值是0,视为假
            s1++;
            s2++;
        }

        // 如果s2已经指向结束符'',则说明在stu开始的位置找到了子串p2,返回stu
        if (*s2 == '') {
            return stu; // 找到子串p2
        }

        // 如果s1已经指向结束符'',说明当前stu所在子串长度不足以匹配p2,终止本次查找
        if (*s1 == '') {
            return NULL;
        }

        // 移动stu指针,使其指向下一个可能的子串起始位置
        *stu++;
    }

    // 遍历结束后仍未找到子串p2,则返回NULL
    return NULL; // 没找到
}

int main() {
    // 定义两个字符串arr1和arr2作为测试数据
    char* arr1 = "abcdabcd";
    char* arr2 = "bcdaaaaaas";

    // 调用自定义my_strstr函数查找arr1中是否存在arr2子串
    const char* ret = my_strstr(arr1, arr2);

    // 根据返回值判断查找结果
    if (ret == NULL) {
        printf("没找到");
    } else {
        printf("%s
", ret); // 输出找到的子串在主串中的起始位置
    }

    // 主函数返回0,表示程序正常执行完毕
    return 0;
}

函数定义与参数介绍

my_strstr函数接受两个const char*类型的指针作为输入参数:p1是指向待搜索的主字符串,p2是指向需查找的子字符串。函数返回一个char*类型的指针,指向子字符串在主字符串中的起始位置,若未找到子字符串,则返回NULL。

函数实现步骤
  1. 初步校验与变量初始化 使用assert宏确保输入的主字符串和子字符串都不为空。然后初始化三个字符指针s1s2stu,其中s1s2将在后续用于遍历主字符串和子字符串,stu初始设置为主字符串的起始地址。
  2. 处理特殊边界情况 如果子字符串p2的第一个字符就是结束符,说明子字符串为空,按照strstr函数的行为规范,直接返回主字符串p1的地址。
  3. 主循环搜索过程 使用一个外层循环遍历主字符串的所有字符,stu指针依次指向每个可能的子串起始位置。
    • 对于每个可能的子串起点,令s1指向stu的当前位置,s2指向子字符串的起始位置。
    • 内层循环同时遍历s1s2,在两者的字符相等且非空的情况下,递进至下一个字符。
    • 当内层循环使s2到达子字符串的结束符时,说明找到了一个完整的子字符串匹配,此时返回s1的初始位置(即stu)。
    • s1先到达结束符,意味着当前子串不能与子字符串完全匹配,跳过内层循环继续搜索。
    • 在每轮外层循环结束后,无论是否匹配成功,都将stu指针前进一位,以便检查下一段可能的子串。
  4. 未找到子字符串时的返回 若遍历完主字符串仍未能找到子字符串,则在循环结束后返回NULL。
int main() {
    char* arr1 = "abcdabcd";
    char* arr2 = "bcdaaaaaas";
    const char* ret = my_strstr(arr1, arr2);
    
    if (ret == NULL) {
        printf("没找到");
    } else {
        printf("%s
", ret);
    }
    
    return 0;
}

输出结果: