模拟实现一些库函数(1)(下)

简介: 模拟实现一些库函数(1)(下)

strcmp

首先该函数是比较函数其中,str1和str2是要进行比较的字符串。函数返回一个整数值来表示比较结果,返回值的含义如下:

若返回值为 0,表示两个字符串相等;

若返回值小于 0,表示str1小于str2;

若返回值大于 0,表示str1大于str2。

我们先看效果

int main()
{
  char str1[] = "ABCD";
  char str2[] = "ABCD";
  char str3[] = "ABC";
  char str4[] = "ABCDF";
  int ret1 = strcmp(str1, str2);
  int ret2 = strcmp(str1, str3);
  int ret3 = strcmp(str1, str4);
  printf("%d\n", ret1);
  printf("%d\n", ret2);
  printf("%d\n", ret3);
  return 0;
}
• 1
• 2
• 3
• 4
• 5
• 6
• 7
• 8
• 9
• 10
• 11
• 12
• 13
• 14

了解了效果后,我们来开始模拟

int my_strcmp(const char* str1, const char* str2)
{
  int ret = 0;
  assert(str1 && str2);
  while (!(ret = *(unsigned char*)str1 - *(unsigned char*)str2) && *str2)
  {
    ++str1;
    ++str2;
  }
  if (ret < 0)
    return -1;
  else if (ret > 1)
    return 1;
  else
    return ret;
}
int main()
{
  char str1[] = "ABCD";
  char str2[] = "ABCD";
  char str3[] = "ABC";
  char str4[] = "ABCDF";
  int ret1 = my_strcmp(str1, str2);
  int ret2 = my_strcmp(str1, str3);
  int ret3 = my_strcmp(str1, str4);
  printf("%d\n", ret1);
  printf("%d\n", ret2);
  printf("%d\n", ret3);
  return 0;
}
• 1
• 2
• 3
• 4
• 5
• 6
• 7
• 8
• 9
• 10
• 11
• 12
• 13
• 14
• 15
• 16
• 17
• 18
• 19
• 20
• 21
• 22
• 23
• 24
• 25
• 26
• 27
• 28
• 29
• 30

我们知道了strcmp的返回值是str1和str2进行比较后得出的,所以函数类型就是int型,在这里只是比较,不希望原字符串有任何改变,所以我们都用const来修饰两个参数,之后我们进入while循环来比较,因为当两个字符串的当前字符相等且尚未到达字符串的结束符时,继续执行循环体,即逐个比较两个字符串的字符,直到出现不同的字符或其中一个字符串到达结束符为止。所以我们设置了这样的循环条件,之后逐个比较str1和str2。

长度受限制的字符串函数

strncpy

该函数和strcpy函数的区别在于多了一个拷贝字符个数限制的条件,由于效果仅在于拷贝个数的限制,所以我们不在看效果,直接开始模拟。

char* my_strncpy(char* str1, size_t size, const char* str2)
{
  char* ret = str1;
  assert(str1 && str2);
  int i = 0;
  while (i < size&&*str2)
  {
    *str1++ = *str2++;
    i++;
  }
  *str1 = '\0';
  return ret;
}
int main()
{
  char str1[] = "***************";
  char str2[] = "hello world!";
  int k = 0;
  printf("请输入拷贝字符个数:");
  scanf("%d", &k);
  my_strncpy(str1, k, str2);
  printf("%s", str1);
  return 0;
}

我们只需要多加一个size_t的参数,来限制拷贝个数即可,注意拷贝完成后,由于个数的限制没有到达结束,所以我们要令循环结束后的str指针也就是拷贝完成后的str指针所指向的内容是’\0’。

strncat

同样的这个函数也只是多了一个追加的个数限制条件。我们直接来模拟这个函数的实现。

char* my_strncat(char* str1, size_t size, const char* str2)
{
  char* ret = str1;
  assert(str1 && str2);
  int i = 0;
  while (*str1)
  {
    str1++;
  }
  while (i < size&&*str2)
  {
    *str1++ = *str2++;
    i++;
  }
  *str1 = '\0';
  return ret;
}
int main()
{
  char str1[20] = "ABCD";
  char str2[] = "EFGHIJKL";
  int k = 0;
  printf("请输入追加字符的个数:");
  scanf("%d", &k);
  my_strncat(str1, k, str2);
  printf("%s", str1);
  return 0;
}

同样的,我们在知道了strcat函数的模拟以及strncpy函数的模拟,仅需要添加一个限制追加字符个数,并且将追加循环完成后str1所指向的内容赋值为’\0’即可。 其他的地方基本和上面几个函数的实现相似。

strncmp

这个函数与strcmp的区别也是多了一个比较个数的限制条件。为了防止大家误会这个函数的效果,我们来看一下这个函数的具体效果,再来模拟实现。

#include <stdio.h>
#include <string.h>
int main() {
    char str1[] = "hello";
    char str2[] = "world";
    int result = strncmp(str1, str2, 3);
    if (result == 0) {
        printf("前 3 个字符相等\n");
    }
    else if (result < 0) {
        printf("str1 小于 str2\n");
    }
    else {
        printf("str1 大于 str2\n");
    }
    return 0;
}

接下来,我们来具体模拟一下该函数

#include <stdio.h>
#include <string.h>
int my_strncmp(const char* str1, const char* str2, size_t size)
{
    int ret = 0;
    assert(str1 && str2);
    int i = 0;
    while (i < size)
    {
        ret = *(unsigned char*)str1 - *(unsigned char*)str2;
        if (ret != 0)
        {
            return ret > 0 ? 1 : -1;
        }
        if (*str1 == '\0')
            break;
        ++str1;
        ++str2;
        i++;
    }
    return 0;
}
int main()
{
    char str1[] = "hello";
    char str2[] = "world";
    int k = 0;
    printf("请输入str1和str2字符比较个数:");
    scanf("%d", &k);
    int result = my_strncmp(str1, str2, k);
    if (result == 0) {
        printf("前 3 个字符相等\n");
    }
    else if (result < 0) {
        printf("str1 小于 str2\n");
    }
    else {
        printf("str1 大于 str2\n");
    }
    return 0;
}

首先也是多了一个限制比较个数的参数,但是有一点不同的是,由于比较完前k个字符,接下来的字符不一定是’\0’,所以我们的代码和实现strcmp有一点不同,一个一个字符来比较即可。

字符串查找函strstr

首先我们了解一下strstr函数的作用:

strstr 函数是C语言标准库 <string.h> 中提供的一个字符串处理函数,用于在一个字符串中查找指定子字符串的第一次出现位置。

函数原型如下:

char* strstr(const char* str1, const char* str2);

strstr 函数接受两个参数:str1 是要搜索的字符串,str2 是要查找的子字符串。

函数返回一个指向 str1 中第一次出现 str2 的位置的指针。如果未找到子字符串,返回 NULL。

来看一下效果:

int main() {
    char str1[] = "Hello, World!";
    char str2[] = "World";
    char* result = my_strstr(str1, str2);
    if (result != NULL) {
        printf("'%s' 第一次出现在 '%s' 中的位置是:%ld\n", str2, str1, result - str1);
    }
    else {
        printf("'%s' 未在 '%s' 中找到\n", str2, str1);
    }
    return 0;
}

接下来我们来模拟实现一下。

#include <stdio.h>
// 自定义实现 strstr 函数
char* my_strstr(const char* str1, const char* str2) {
    assert(str1);
    // 如果 str2 为空字符串,则直接返回 str1
    if (*str2 == '\0') {
        return (char*)str1;
    }
    // 遍历 str1
    while (*str1 != '\0') {
        const char* p1 = str1;
        const char* p2 = str2;
        // 在 str1 中查找 str2
        while (*p1 == *p2 && *p1 != '\0') {
            p1++;
            p2++;
        }
        // 如果 p2 指向了 str2 的结尾,说明找到了 str2,返回位置
        if (*p2 == '\0') {
            return (char*)str1;
        }
        // 在 str1 中继续查找
        str1++;
    }
    // 没有找到 str2,返回 NULL
    return NULL;
}
int main() {
    char str1[] = "Hello, World!";
    char str2[] = "World";
    char* result = my_strstr(str1, str2);
    if (result != NULL) {
        printf("'%s' 第一次出现在 '%s' 中的位置是:%ld\n", str2, str1, result - str1);
    }
    else {
        printf("'%s' 未在 '%s' 中找到\n", str2, str1);
    }
    return 0;
}

首先,我们需要两个字符串数组参数,在str1中寻找str2,由于我们只是寻找,并不希望原字符串发生改变,所以我们在接受参数时用const来修饰一下,如果str2指向的是空指针那么我们直接返回str1,如果不是进入我们的代码中,遍历str1,我们把str1和str2赋给p1和p2,然后设置一个如果存在才能进入的循环,然后给一个if语句,如果p2解引用等于‘\0’,说明str2到了末尾,也就是找到了,我们返回这个时候的str1指针所指向的位置,之后在if语句外str1++,如果没有碰到str2就遍历str1,这样我们最后遍历完str1,就能知道str2是否存在于str1中了。

总结

相信大家能看出来模拟这些函数有很多地方都是很相似的,那么就分享到这里,各位看客老爷万福金安。

目录
相关文章
|
存储 数据挖掘 区块链
《区块链公链数据分析简易速速上手小册》第3章:区块链数据结构(2024 最新版)(下)
《区块链公链数据分析简易速速上手小册》第3章:区块链数据结构(2024 最新版)(下)
163 0
|
SQL 数据库连接 数据库
Access 与SQL Server 2000
一、将Access 数据库数据移植转换为SQL Server 2000 第一步,开启SQLSERVER 2000服务管理,打开“企业管理器”,新建一个数据库,名称为“Access数据转换”; 第二步,运行“导入和导出数据”,打开“DTS导入/导出向导”。
905 0
|
6天前
|
存储 关系型数据库 分布式数据库
PostgreSQL 18 发布,快来 PolarDB 尝鲜!
PostgreSQL 18 发布,PolarDB for PostgreSQL 全面兼容。新版本支持异步I/O、UUIDv7、虚拟生成列、逻辑复制增强及OAuth认证,显著提升性能与安全。PolarDB-PG 18 支持存算分离架构,融合海量弹性存储与极致计算性能,搭配丰富插件生态,为企业提供高效、稳定、灵活的云数据库解决方案,助力企业数字化转型如虎添翼!
|
17天前
|
弹性计算 关系型数据库 微服务
基于 Docker 与 Kubernetes(K3s)的微服务:阿里云生产环境扩容实践
在微服务架构中,如何实现“稳定扩容”与“成本可控”是企业面临的核心挑战。本文结合 Python FastAPI 微服务实战,详解如何基于阿里云基础设施,利用 Docker 封装服务、K3s 实现容器编排,构建生产级微服务架构。内容涵盖容器构建、集群部署、自动扩缩容、可观测性等关键环节,适配阿里云资源特性与服务生态,助力企业打造低成本、高可靠、易扩展的微服务解决方案。
1320 7
|
5天前
|
存储 人工智能 Java
AI 超级智能体全栈项目阶段二:Prompt 优化技巧与学术分析 AI 应用开发实现上下文联系多轮对话
本文讲解 Prompt 基本概念与 10 个优化技巧,结合学术分析 AI 应用的需求分析、设计方案,介绍 Spring AI 中 ChatClient 及 Advisors 的使用。
296 129
AI 超级智能体全栈项目阶段二:Prompt 优化技巧与学术分析 AI 应用开发实现上下文联系多轮对话
|
4天前
|
监控 JavaScript Java
基于大模型技术的反欺诈知识问答系统
随着互联网与金融科技发展,网络欺诈频发,构建高效反欺诈平台成为迫切需求。本文基于Java、Vue.js、Spring Boot与MySQL技术,设计实现集欺诈识别、宣传教育、用户互动于一体的反欺诈系统,提升公众防范意识,助力企业合规与用户权益保护。
|
16天前
|
机器学习/深度学习 人工智能 前端开发
通义DeepResearch全面开源!同步分享可落地的高阶Agent构建方法论
通义研究团队开源发布通义 DeepResearch —— 首个在性能上可与 OpenAI DeepResearch 相媲美、并在多项权威基准测试中取得领先表现的全开源 Web Agent。
1392 87