IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 常见库函数的模拟实现 -> 正文阅读

[C++知识库]常见库函数的模拟实现

一、库函数的模拟实现

库函数是将函数封装入库,供用户使用的一种方式

今天我将会和大家分享一些我们常用的一些库函数以及它们的模拟实现

1.模拟实现strlen

首先我们需要先了解一下strlen的功能以及其实现功能的大致方法。

strlen是我们计算字符串长度时使用的一个库函数,知道遇到空字符串时停止计算,到不包括空结束字符串。

以下是strlen()函数的声明:

size_t strlen(const char *str) 

先来说说我的思路:首先我们先传入一个字符串到我们自己模拟实现的函数里面,然后逐个字符进行统计,直到遇到’\0’停下,具体代码如下:

#include <stdio.h>
#include <assert.h>

int my_strlen(const char* str)
{
	int count = 0;
	assert(str);  //非空指针
	while (*str != '\0')
	{
		str++;
		count++;
	}
	return count;
}

int main()
{
	char arr[] = "abcdef";
	int len = my_strlen(arr);
	printf("%d", len);
	return 0;
}

strlen的实现逻辑是较为简单明了的,大家可以自己按照自己的思路尝试模拟实现一下。

2.模拟实现strcpy

C 库函数 strcpy把 一个字符串的内容复制到另一个字符串上

需要注意的是如果目标数组不够大,而源字符串的长度又太长,可能会造成缓冲溢出的情况

声明如下:

char *strcpy(char *dest, const char *src)	

实现逻辑能其实也很容易理解,首先我们要把字符串传入我们的模拟实现函数中,注意形参我们要以char*的形式接收,因为我们的实参是以数组名的形式传入的,传入的是首元素的地址。然后我们就可以通过使用while语句来实现字符之间的复制,判断的标准自然就是src解引用后是否是’\0’,如果不是我们则继续复制,是的话我们就跳出该地址。但是由于在循环过程中我们的dest的地址是不断在变化的,所以我们最好把初始的dest地址存放在另一个地址中。具体实现如下:

#include <stdio.h>
#include <assert.h>

int my_strcpy( char* dest,const char* src)//这里用const修饰所指向的源字符串,因为源字符串是 常量字符串,不能被修改                                          
{
	assert(dest && src);  //断言源字符串和目标空间都不能为空指针
	char* ret = dest;   //记录初始位置
	while (*src != '\0')
	{
		*dest = *src;        
		dest++;          //一个字符串一个字符串的拷贝,遇到'\0'结束
		src++;        
	}
	return ret;        //返回目标空间的起始地址

}

int main()
{
	char arr1[] = "abcdef";
	char arr2[20] = { 0 };
	my_strcpy(arr2, arr1);
	printf("%s\n", arr2);

	return 0;
}

3.模拟实现strcat

对于这个函数,我们先来看看函数的声明会更有利于我们理解该函数的功能:

char *strcat(char *dest, const char *src)

我们可以看到,strcat形参的形式和strcpy十分相似,而C库函数 strcat是把 src 所指向的字符串追加到 dest 所指向的字符串的结尾。

实现的逻辑其实也不是十分复杂,首先我们需要找到目标空间的结束标志处,也就是’\0’,然后再开始我们连接的现实。连接的话就十分简单了,只需要从我们寻找到的目标结束标志处开始把另一字符串的内容逐步复制过来,模拟实现该函数的代码如下:

#include <stdio.h>
#include <assert.h>

int my_strcat( char* dest, char* src)
{
	assert(dest && src);
	char* ret = dest;   //记录初始位置
	while (*dest != '\0')   //找到目标空间的结束标志处,然后开始连接
	{
		dest++;
	}			  
	while (*dest++ = *src++)
	{
		;
	}
	return ret;
}

int main()
{
	char arr1[20] = "hello";
	my_strcat(arr1,"world");
	printf("%s\n", arr1);
	return 0;
}  

4.模拟实现strstr

同样的,我们先来看strstr函数的声明:

char *strstr(const char *haystack, const char *needle)

C 库函数 strstr在字符串 haystack 中查找第一次出现字符串 needle 的位置,不包含终止符 ‘\0’。

strstr函数的实现逻辑相较于前面几个C库函数会复杂一点点

首先我们需要传入两个字符串,然后将各自的初始地址先分别存入另外的指针。然后我们就可以利用循环语句,判断条件其实很简单,以是否遇到结束标志’\0’为标准。然后我们分别从两个字符串的第一个字符开始寻找,这里往下继续寻找的条件要考虑全面。无论是哪个字符串都不可以是’\0’,并且需要两个字符是相等的。就这样不断寻找下去,如果找不到则将我们传入的第一个字符串的首元素地址向下推移一个字符,以此类推,直到知道和传入的第二个字符串相同的一段字符,然后输出它,如果直到最后都没有相同字符串部分,则会返回空指针。

#include <stdio.h>
#include <assert.h>

char* my_strstr(const char* str1, const char* str2)
{
	assert(str1 && str2);
	const char* s1 = str1;
	const char* s2 = str2;
	const char* p = str1; 
	while (*p)
	{
		s1 = p;
		s2 = str2;
		while (*s1 != '\0' && *s2 != "\0" && *s1 == *s2)
		{
			s1++;
			s2++;
		}
		if (*s2 == '\0')
		{
			return (char*)p;
		}
		p++;
	}
	return NULL;
}
int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "def";
	char* ret = strstr(arr1, arr2);
	if (ret == NULL)
	{
		printf("字符串不存在\n");
	}
	else
	{
		printf("%s\n", ret);
	}
	return 0;
}

5.模拟实现strcmp

先来看C库函数strcmp的声明:

int strcmp(const char *str1, const char *str2)

C 库函数把 str1 所指向的字符串和 str2 所指向的字符串进行比较。

这个函数的实现逻辑就非常简单的,传入两个字符串,从第一个字符开始比较,然后往后一个一个对比即可,具体模拟实现代码如下:

#include <assert.h>
int my_strcmp(char* str1, char* str2)
{
	assert(str1 && str2);
	while (*str1 == *str2) //先看首字符是否相等,如果相等,继续比下去
	{
		if (*str1 == '\0')//判断是否比完所有字符,返回0,说明两个字符相等
		{
			return 0;
		}
		else
		{
		  str1++;
		  str2++;
		}
	}
	//如果两个字符不相等,那就比大小,返回大于0的数则说明str1>str2,反之小于
	return (*str1 - *str2);
}
int main()
{
	char arr1[20] = "abcd";
	char arr2[20] = "abc";
	int ret=my_strcmp(arr1,arr2);
	if (ret < 0)
	{
		printf("<\n");
	}
	else if (ret == 0)
	{
		printf("==\n");
	}
	else
	{
		printf(">\n");
	}

	return 0;
}

6.模拟实现memcpy

这个函数传入的参数和之前的函数都有些许差异,我们先来看看它的声明:

void *memcpy(void *str1, const void *str2, size_t n)

先来给大家解释一下这些个参数的含义

  • str1 – 指向用于存储复制内容的目标数组,类型强制转换为 void* 指针。
  • str2 – 指向要复制的数据源,类型强制转换为 void* 指针。
  • n – 要被复制的字节数。

C 库函数 void *memcpy(void *str1, const void *str2, size_t n) 的功能是从存储区 str2 复制 n 个字节到存储区 str1

memcpy的实现逻辑和strcpy有所不同。首先我们需要传入我们上面讲到的几个参数,具体的一些注释我们放在了下面的模拟实现代码中。大致的思路就是利用循环语句,将str1中的n个字节复制到str2的n个字节中,这里的n个字节就是我们之前传入的size_t num。

#include <stdio.h>
#include <assert.h>

void* my_memcpy(void* dest, const void* src, size_t num) //因为memcpy是内存拷贝函数,所以必须什么类型都能接收,所以此处用void*做参数类型和返回值类型
{
    assert(dest && src);
    void* ret = dest; //因为dest在循环体中不断发生变化,所以将dest的地址存放在指针变量ret中,此后ret就随着dest进行变化,但dest不会随着ret进行变化,最后函数返回ret的值

    while (num--)
    {
        *(char*)dest = *(char*)src;   //最少单位是char,强制转换最小类型,然后一个一个字节替换
        dest = (char*)dest + 1;    //void*类型不能进行++操作,这里也强制转换类型.
        src = (char*)src + 1;
    }

    return ret;
}

//arr1打印输出函数
void print(int arr1[], int sz)
{
    int i = 0;
    for (i = 0; i < sz; i++)
    {
        printf("%d ", arr1[i]);
    }
    printf("\n");
}

int main()
{

    int arr1[10] = { 0 };
    int arr2[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    my_memcpy(arr1, arr2, 40);//此处n是字节数,40个字节也就是10个int型值
    int sz = sizeof(arr1) / sizeof(arr1[0]);
    print(arr1, sz);
    system("pause");
    return 0;
}

7.模拟实现memmove

先来看看memmove函数的声明:

void *memmove(void *str1, const void *str2, size_t n)

C 库函数 void *memmove(void *str1, const void *str2, size_t n)str2 复制 n 个字符到 str1,但是在重叠内存块这方面,memmove() 是比 memcpy() 更安全的方法。如果目标区域和源区域有重叠的话,memmove() 能够保证源串在被覆盖之前将重叠区域的字节拷贝到目标区域中,复制后源区域的内容会被更改。如果目标区域与源区域没有重叠,则和 memcpy() 函数功能相同。

我们来看看模拟实现的代码:

#include <stdio.h>
#include <assert.h>

void* my_memmove(void* dest, const void* src, size_t num)
{
    assert(dest && src);
    void* ret = dest;
    if (dest < src) //两个地址的大小 
    {
        //前->后
        while (num--)
    {
        *(char*)dest = *(char*)src;
        dest = (char*)dest + 1;
        src = (char*)src + 1;
    }

    }
    else
    {
        // 后->前
        while (num--)          //num-1个字节
        {                           
            *((char*)dest + num) = *((char*)src + num);
        }
    }
    return ret;
}

//arr1打印输出函数
void print(int arr1[], int sz)
{
    int i = 0;
    for (i = 0; i < sz; i++)
    {
        printf("%d ", arr1[i]);
    }
    printf("\n");
}

int main()
{
    int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
    my_memmove(arr1+2, arr1,20);
    int sz = sizeof(arr1) / sizeof(arr1[0]);
    print(arr1, sz);
    system("pause");
    return 0;
}
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-07-21 21:19:47  更:2022-07-21 21:21:49 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/9 15:20:06-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码