目录
我们的库函数可以很方便快速的帮我们实现一些问题,今天我们通过模拟实现的方式来深刻理解这些库函数的运作逻辑。我们找到这些常用的库函数。
1.strcpy | 拷贝字符串 |
2.strcat | 追加字符串 |
3.strcmp | 比较字符串 |
4.strstr | 查找字符串 |
5.strncpy | 计量拷贝字符串 |
6.strncat | 计量追加字符串 |
7.strncmp | 计量比较字符串 |
8.memcpy | 内存拷贝 |
9.memove | 内存移动 |
一、Strcpy(拷贝字符串)
我们首先分析这个函数的参数和功能。返回目标字符串指针 Strcpy(目标字符串,待拷贝字符串)。作用是将待拷贝字符串的所有内容复制到目标字符串中。参数部分就是两个字符串类型。
我们模拟实现时,选用两个字符指针作为参数,其中为了防止待拷贝字符串被误修改,我们还可以设置成const类型。返回类型写成字符指针即可。
char* my_strcpy(char* dest,const char* str);
参数部分写好后,分析运行逻辑,为了将一个字符串的内容复制到另一个字符串,我们只需要将里面的内容一个个的直接赋值过去,直到待拷贝的字符串遇到'\0',为了返回目标字符串的首元素地址,我们在复制前先用字符指针来保存。
char* my_strcpy(char* dest,const char* str)
{
char* ret = dest; //保存目标首元素地址
while(*str!='\0')//直到遇到终止字符
{
*dest=*str;//拷贝内容
//进入下一个
dest++;
str++;
}
*dest = '\0';//不要忘了放置终止字符
return ret;
}
二、Strcat(追加字符串)
我们首先分析这个函数的参数和功能。返回目标字符串指针 Strcat(目标字符串,待追加字符串)。作用是在目标字符串的末尾添加待追加字符串。参数部分就是两个字符串类型。
我们模拟实现时,选用两个字符指针作为参数,其中为了防止待追加字符串被误修改,我们还可以设置成const类型。返回类型写成字符指针即可。这个模拟实现和字符串拷贝一模一样,只需将目标拷贝的起始位置更改到末尾处即可。值得注意的是,目标能够容的下那么多的内容。
char* my_strcat(char* dest,const char* str);
char* my_strcat(char* dest,const char* str)
{
char* ret = dest; //保存目标首元素地址
while(*dest!='\0')//找到目标末尾地址
{
dest++;
}
while(*str!='\0')//直到遇到终止字符
{
*dest=*str;//追加内容
//进入下一个
dest++;
str++;
}
*dest = '\0';//不要忘了放置终止字符
return ret;
}
三、strcmp(比较字符串)
我们同样首先分析这个函数的参数和功能。int Strcmp(目标字符串,比较字符串)。作用是比较字符串每个对应元素字符的ASCLL码值,大的返回1,小的返回-1,相等返回0。参数部分就是两个字符串类型。
我们模拟实现时,选用两个字符指针作为参数,其中为了防止这些字符串被误修改,我们还可以设置成const类型。返回类型写成能接收数字的整型即可。
int my_strcmp(const char* dest,const char* str);
int my_strcmp(const char* dest,const char* str)
{
while(*dest==*str)//找到不相等的位置
{
dest++;
str++;
}
if(*dest!='\0'||*str!='\0')//只要两个字符串其中一个不是末尾,说明提前停下来
{
return *dest - *str;//直接返回差值
}
else//说明都走到了末尾,一定相等
{
return 0;
}
}
四、strstr(查找字符串)
我们同样首先分析这个函数的参数和功能。返回目标字符串包含查找字符串的起始地址 Strstr(目标字符串,待查找字符串)。作用是查找目标字符串中是否包含待查找字符串,找到了返回找到的起始位置,没找到就返回一个空指针。参数部分就是两个字符串类型。
我们模拟实现时,选用两个字符指针作为参数,其中为了防止这些字符串被误修改,我们还可以设置成const类型。为了找到对应字符串,我们要额外设置指针指向开始查找的位置和待查找的字符串起始位置,因为我们要比较每一位都是否相等,只要有一个不同就不是同一个字符串。我们每次记录双方的起始位置后,依次比较每个字符,只要有一个不同,目标指针从下一个开始找,查找字符串的指针重新指向起始位置,直到查找字符串的指针指向了'\0'说明找到了。
char* my_strstr(const char* dest,const char* str);
char* my_strstr(const char* dest,const char* str)
{
char* p1=dest;
char* p2=str;
while(*dest!='\0')
{
p1=dest;//重新开始
p2=str;//重置进度
while(*p1=*p2)
{
p1++;
p2++;
if(*p2=='\0')//找到了
{
return dest;
}
}
dest++;//找下一个
}
return NULL;//没找到,返回空指针
}
五、计量拷贝字符串(Strncpy)
和拷贝字符串strcpy的区别是多了个n,也就是数量num,它只会拷贝一定量的元素,如果待拷元素还不够,遇到‘\0’也是不会停的,会不断补充'\0'进入目标字符串,参数部分多了个要拷贝的数量。
char* my_strcpy(char* dest,const char* str,size_t num);
char* my_strncpy(char* dest,const char* str,size_t num)
{
char* ret = dest; //保存目标首元素地址
while(num--)//直到拷贝完
{
*dest=*str;//拷贝内容
//进入下一个
dest++;
if(*str!='\0')
{
str++;
}
}
return ret;
}
六、计量追加字符串(Strncat)
和计量拷贝同理,只会追加一定量的元素,这里我们快速实现一下。
char* my_strcat(char* dest,const char* str,size_t num);
char* my_strncat(char* dest,const char* str,size_t num)
{
char* ret = dest; //保存目标首元素地址
while(*dest!='\0')//找到目标末尾地址
{
dest++;
}
while(num--)//直到追加完
{
*dest=*str;//追加内容
//进入下一个
dest++;
if(*str!='\0')
{
str++;
}
}
return ret;
}
七、计量比较字符串(Strncmp)
同理我们都只要不循环部分终止部分改成直到num用完。
int my_strncmp(char* dest,const char* str,size_t num);
int my_strcmp(const char* dest,const char* str)
{
while(*dest==*str&&num--)//找到不相等的位置
{
dest++;
str++;
}
if(*dest!='\0'||*str!='\0')//只要两个字符串其中一个不是末尾,说明提前停下来
{
if(*str==*dest)//因为可能存在num用完的情况
{
return 0;
}
return *dest - *str;//不相等返回差值
}
else//说明都走到了末尾,一定相等
{
return 0;
}
}
八、内存拷贝(Memcpy)
这下我们都直到字符是怎么拷贝过去的了,但如果遇到整型数组,又该如何拷贝,这个时候就要用到内存拷贝了,我们通过拷贝内存的值,来拷贝一个整型的所有组成部分,内存拷贝就是这样工作的。我们无需考虑传进来的是什么类型,我们只负责拷贝每个字节的内容,不负责类型,所以我们可以将参数设为void*类型来接收各种不同的数据类型,num来作为要拷贝字节的数量。
void* my_memcpy(void* dest,const void* str,size_t num);
void* my_memcpy(void* dest,const void* str,size_t num)
{
void* ret = dest;
//为了一个字节一个字节的拷贝,我们要将指针强制类型转化为char*指针
while(num--)
{
*(char*)dest=*(char*)str;
dest=(char*)dest+1;//找下一个也是只跳一个字节
str=(char*)str+1;
}
return ret;
}
九、内存移动(Memove)
由于如果我们要内存拷贝的内容是自己本身都话,容易导致内存拷贝的部分被原来的覆盖,所以memove函数是用来专门拷贝字符串本身的,也叫内存移动。
void* my_memove(void* dest,const void* str,size_t num);
void* my_memove(void* dest,void* str,size_t num)
{
void* ret = dest;
if (dest < str)//目标地址小于拷贝地址,从头开始拷贝
{
while (num--)
{
*(char*)dest = *(char*)str;
dest = (char*)dest+1;
str = (char*)str + 1;
}
}
else//目标地址大于拷贝地址,从尾巴往头开始拷贝
{
dest = (char*)dest + num;
str = (char*)str + num;
while (num--)
{
*(char*)dest = *(char*)str;
dest = (char*)dest - 1;
str = (char*)str - 1;
}
}
return ret;
}