@[TOC]
memcpy函数
memcpy函数分析
首先这个函数的功能是用来进行内存拷贝的,仿照与strcpy,那么关于它的定义有如下解释
从图中可以看出,函数拥有三个参数,destination(目的地),source(来源于哪),num(需要几个字节),而函数的功能如下:Copies the values of num bytes from the location pointed to by source directly to the memory block pointed to by destination.
即将源头的内容拷贝到目的地中,拷贝num个==字节==
在这里回顾void*
void*是一个万能指针,它可以接收任意类型的指针,但相应的这是有代价的,你不能通过它直接取出里面的内容,需要将它强制转化为某种类型的指针,才能将它取出
而在这个函数中,由于我们不知道具体要拷贝什么类型的函数,于是我们就直接将这个指针类型设置为void*
那么有了上面的分析,模拟实现如下
memcpy模拟实现
//模拟实现memcpy
#include <stdio.h>
#include <string.h>
void* my_memcpy(void* arr2, void* arr1, size_t size)
{
while (size--)
{
*(char*)arr2 = *(char*)arr1;
(char*)arr2 = (char*)arr2 + 1;
(char*)arr1 = (char*)arr1 + 1;
}
}
int main()
{
int arr1[10] = {
1,2,3,4,5,6,7,8,9 };
int arr2[20] = {
0 };
//memcpy(arr2, arr1, 16);
my_memcpy(arr2, arr1, 16);
for (int i = 0; i < 10; i++)
{
printf("%d ", arr2[i]);
}
return 0;
}
memmove函数
memmove函数分析
其实memmove函数和memcpy函数功能基本类似,在有些编译器上它们的功能甚至会被手动优化,那么有什么区别?
我们来看下面的例子,输出结果是多少?
void* my_memcpy(void* arr2, void* arr1, size_t size)
{
void* ret = arr2;
while (size--)
{
*(char*)arr2 = *(char*)arr1;
(char*)arr2 = (char*)arr2 + 1;
(char*)arr1 = (char*)arr1 + 1;
}
return ret;
}
int main()
{
int arr1[10] = {
1,2,3,4,5,6,7,8,9 };
int arr2[10] = {
0 };
//my_memmove(arr1+2, arr1, 16);
my_memcpy(arr1 + 2, arr1, 16);
for (int i = 0; i < 10; i++)
{
printf("%d ", arr1[i]);
}
return 0;
}
输出结果如下
==为什么?==
这段代码的目的是把arr的数据复制到arr+2的地方去,总共复制16个字节的内容,图示如下:
问题就在于3和4上,这两个元素是有重叠部分的,在这个部分内的元素会发生重叠,导致拷贝出错,出错原因如下:
如下图,当内存中开始取代时,重叠部分的区域会来回取代,这样就导致了刚才输出的异常,那么解决方法就是现在的这个memmove函数
这个函数的功能强大在于,它可以根据dest和reso的位置确定是从前往后拷贝还是从后往前拷贝,对于上面这个情况,如果我们采取的是从后向前拷贝,模式图如下:
在这种模式下就可以做到拷贝,那么总结一下就得到了下面的函数实现
memmove模拟实现
void* my_memmove(void* dest, void* reso, size_t size)
{
void* ret = dest;
if (reso > dest)
{
while (size--)
{
*(char*)dest = *(char*)reso;
(char*)dest = (char*)dest + 1;
(char*)reso = (char*)reso + 1;
}
}
else
{
while (size--)
{
*((char*)dest + size) = *((char*)reso + size);
}
}
return ret;
}
void* my_memcpy(void* arr2, void* arr1, size_t size)
{
void* ret = arr2;
while (size--)
{
*(char*)arr2 = *(char*)arr1;
(char*)arr2 = (char*)arr2 + 1;
(char*)arr1 = (char*)arr1 + 1;
}
return ret;
}
int main()
{
int arr1[10] = {
1,2,3,4,5,6,7,8,9 };
int arr2[10] = {
0 };
my_memmove(arr1+2, arr1, 16);
//my_memcpy(arr1 + 2, arr1, 16);
for (int i = 0; i < 10; i++)
{
printf("%d ", arr1[i]);
}
return 0;
}
从这个函数体中能看出,实际上是分为两种情况,一种情况是如果源头在目标的前面,就从前向后拷贝,如果在后面就从后向前拷贝
用这种很巧妙的方式解决了这个问题
strstr函数
strstr函数分析
==char strstr(const char haystack, const char *needle)==
在字符串 haystack 中查找第一次出现字符串 needle 的位置,不包含终止符 '\0'。
这是一个查找字符串的函数,在一段字符串中查找指定的字符串,如果找到了就返回地址
strstr函数模拟实现
//strstr模拟实现
#include <stdio.h>
char* my_strstr(const char* str1, const char* str2)
{
char* s1 = (char*)str1;
char* s2 = (char*)str2;
char* cp = (char*)str2;
while (*cp)
{
s1 = cp;
s2 = (char*)str2;
while (*s1 && *s2 && *s1 == *s2)
{
s1++;
s2++;
}
if (*s2 == '\0')
{
return cp;
}
}
return NULL;
}
int main()
{
char str1[] = {
"abcde" };
char str2[] = {
"bcd" };
printf("%s\n", my_strstr(str1, str2));
return 0;
}
strlen函数
函数分析
字符串函数中应用最广的函数之一,主要作用是寻找字符串中的\0,并记录在这之前有多少个字符,用来计算==字符串==的长度
strlen函数模拟实现
下面展示了三种strlen函数的模拟实现方式,指针,递归,和计数器
//strlen函数模拟
#include <stdio.h>
#include <string.h>
//计数器
size_t my_strlen1(const char* arrr)
{
int ret = 0;
while (*arrr != '\0')
{
ret++;
arrr++;
}
return ret;
}
//指针-指针
size_t my_strlen2(const char* arr)
{
int ret = 0;
const char* p = arr;
while (*arr != '\0')
{
arr++;
}
ret =(int)(arr - p);
return ret;
}
//递归
size_t my_strlen3(const char* str)
{
if (*str == '\0')
{
return 0;
}
else
{
return 1 + my_strlen3(str + 1);
}
}
int main()
{
char arr[] = "abcd";
int len1 = (int) my_strlen1(arr);
int len2 = (int)my_strlen2(arr);
int len3 = (int)my_strlen3(arr);
printf("%d\n", len1);
printf("%d\n", len2);
printf("%d\n", len3);
return 0;
}
strcpy函数
strcpy函数分析
strcpy函数又叫做字符串拷贝函数,运用场景通常是需要把一个字符串赋予给另外一个字符串时,由于语法限定不可以使用==arr1=arr2==这种语句用来赋值,于是诞生了字符串复制函数。
字符串函数通常都和\0有关,这个函数也不例外,这个函数的原理就是找到字符串中的\0并把它前面的内容复制到另外一个字符串中
strcpy函数模拟实现
//strcpy函数模拟
#include <stdio.h>
void my_strcpy1(char* arr2, const char* arr1)
{
do
{
*arr2 = *arr1;
arr2++;
arr1++;
} while (*arr1 != '\0');
}
char* my_strcpy2(char* str2, const char* str1)
{
char* ret = str1;
while (*str2++ = *str1++);
return ret;
}
int main()
{
char arr1[] = {
"abcdef" };
char arr2[10] = {
0 };
char arr3[10] = {
0 };
my_strcpy1(arr2, arr1);
my_strcpy2(arr3, arr1);
printf("%s\n", arr1);
printf("%s\n", arr2);
printf("%s\n", arr3);
printf("%s\n", my_strcpy2(arr3, arr1));
return 0;
}
strcat函数
strcat函数分析
strcat函数也叫做字符串追加函数,在指定的字符串后追加要追加的部分
strcat函数模拟实现
//strcat函数模拟
#include <stdio.h>
#include <string.h>
char* my_strcat(char* arr1, char* arr2)
{
char* ret = arr1;
while (*arr1 != '\0')
{
arr1++;
}
while (*arr2 != '\0')
{
*arr1 = *arr2;
arr2++;
arr1++;
}
return ret;
}
int main()
{
char arr1[20] = "abcdef";
char arr2[] = "ghi";
printf("%s\n", my_strcat(arr1, arr2));
return 0;
}
strcmp函数
strcmp函数分析
这个函数也叫做字符串比较函数,给定两个字符串进行比较,比较的是字符串的ASCII码值,如果相等进行下一个,直到必出大小或遇到\0
如果A字符串大于B字符串,返回一个大于0的数,小于返回一个小于0的数,如果相等则返回0
strcmp函数模拟实现
//strcmp函数模拟
#include <stdio.h>
#include <string.h>
int my_strcmp(char* arr1, char* arr2)
{
int ret = 0;
while (*arr1 != '\0' && *arr2 != '\0')
{
if (*arr1 > *arr2)
{
ret = 1;
break;
}
else if (*arr1 < *arr2)
{
ret = -1;
break;
}
else
{
arr1++;
arr2++;
}
}
return ret;
}
int main()
{
char arr1[] = {
"abcde" };
char arr2[] = {
"abcde\0fg" };
int len = my_strcmp(arr1, arr2);
printf("%d", len);
return 0;
}