一、库函数的模拟实现
库函数是将函数封装入库,供用户使用的一种方式
今天我将会和大家分享一些我们常用的一些库函数以及它们的模拟实现
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)
{
assert(dest && src);
char* ret = dest;
while (*src != '\0')
{
*dest = *src;
dest++;
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')
{
return 0;
}
else
{
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)
{
assert(dest && src);
void* ret = dest;
while (num--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
return ret;
}
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);
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--)
{
*((char*)dest + num) = *((char*)src + num);
}
}
return ret;
}
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;
}
|