目录
模拟实现:
1. memcpy
memcpy函数的作用为:将source指向的地址拷贝num个字节到destination指向的的地址
(注意!这里时拷贝num个字节!)
返回类型为void*类型,返回destination指向的起始地址
前两个参数均为void*类型,
第一个参数为拷贝的目的地的起始地址;
第二个参数为要拷贝的内容所在的起始地址;
第三个参数为size_t类型,即无符号整型类型,num为要拷贝的字节数;
与strnmpy函数差不多,只不过memcpy函数可以拷贝任意类型的数据。
EX:
#include <stdio.h>
#include <string.h>
int main()
{
int arr1[15] = { 0 };
int arr2[] = { 1,2,3,4,5,6,7,8,9,10 };
memcpy(arr1, arr2, 20);
return 0;
}
该样例是将arr2指向的地址的前20个字节的内容拷贝到arr1指向的地址中,因为这些数据的类型均为int类型,一个int类型占4个字节,拷贝20个字节就是拷贝5个int类型的数据。
#include <stdio.h>
#include <string.h>
int main()
{
float arr1[15] = { 0 };
float arr2[] = { 1.0f,2.0f,3.0f,4.0f,5.0f,6.0f,7.0f };
memcpy(arr1, arr2, 20);
return 0;
}
该样例是拷贝float类型数据,同理,拷贝20个字节的内容就是拷贝5个float类型的数据。
PS:
该函数遇到'\0'也不会停止,直到拷贝完规定的字节为止~
#include <stdio.h>
#include <string.h>
int main()
{
int arr1[15] = { 0 };
int arr2[] = { 1,2,3 };
memcpy(arr1, arr2, 20);
return 0;
}
arr2中只有3个int类型的数据,可是memcpy函数要拷贝20个字节的数据,
通过监视我们可以看到,拷贝完3个int类型的数据之后,不管后面是不是'\0',只要没有拷贝完规定的字节数,都会往后继续拷贝~
模拟实现:
创建一个my_memcpy函数,模拟实现memcpy函数功能:
void* my_memcpy(void* dest, const void* sur, size_t num)//返回值类型参数类型与原函数保持一致
{//dest所指向的字符串需要被修改,不用const保护,src所指向的字符串不需要被修改用const修饰保护
assert(dest && sur);//断言一下,保证两个指针均不为空指针,若为空指针则中止程序并报错
void* ret = dest;//创建一个char*变量保存起始地址,后面需要返回起始地址
while (num--)//控制拷贝几个字节
{
*(char*)dest = *(char*)sur;//char类型为一个字节,强制类型转化为char类型就可以一个节一个字节拷贝
(char*)dest += 1; //强制类型转化为char*再+1,就跳过一个字节大小
(char*)sur += 1; //同理
}
return ret; //返回所保存的起始地址
}
int main()
{
char arr1[] = "abcdef";
char arr2[] = "qwer";
my_memcpy(arr1, arr2, 4);
printf("%s\n", arr1);
return 0;
}
该函数不能拷贝重合的情况!
2. memmove
memmove函数的作用:与memcpy函数的作用相同~
和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
如果源空间和目标空间出现重叠,就得使用memmove函数处理。
EX:
int main()
{
int arr[15] = { 1,2,3,4,5,6,7,8,9,10 };
memmove(arr + 2, arr, 20);
return 0;
}
该样例就十分直观了,将arr内存块的内容拷贝20个字节到arr+2的内存块,
显然有重叠的部分,但是memmove函数可以完美解决重叠的问题~
模拟实现:
创建一个my_memmove函数,模拟实现memmove函数功能:
void* my_memmove(void* dest, const void* sur, size_t num)
{
assert(dest && sur);
void* ret = dest; //以上代码与前几个模拟函数类似,这里就不多赘述了
if (dest < sur)
{
while (num--)
{
*(char*)dest = *(char*)sur; //强制类型转化为char*类型,因为char类型就是占用一个字节
dest = (char*)dest + 1;
sur = (char*)sur + 1;
}
}
else
{
while (num--)
{
*((char*)dest + num) = *((char*)sur + num);//这里不用再-1了,while判断之后就自动-1了。
}
}
return ret;
}
int main()
{
char arr1[] = "abcdef";
my_memmove(arr1 + 2, arr1, 4);
printf("%s\n", arr1);
return 0;
}
这里只解释拷贝重合的情况:(其余都与my_memcpy函数类似)
第一种情况:src在dest前面
若从前向后拷贝那么重合的部分就会被提前更改,导致后面拷贝的内容是已经被更改完的,结果错误
所以,这种情况我们需要从后向前拷贝,先拷贝重叠部分,之后被覆盖的时候就没有影响了
第二种情况:src在dest后面
这种情况也是先拷贝重叠部分,即从前向后拷贝,之后重叠部分被覆盖的时候也是没有影响的
3. memcmp
memcmp函数的作用:比较ptr1与ptr2内存块的num个字节的内容~
前两个参数就是要比较的内存块的地址;
第三个参数就是要比较的字节数。
返回值为int类型:
EX:
int main()
{
int arr1[] = { 1,2,3,4,5 };
int arr2[] = { 1,2,3,0,0 };
int ret = memcmp(arr1, arr2, 12);
printf("%d\n", ret);
return 0;
}
前12个字节的内容都一样,所以返回0
PS:
要注意的是:
这里比较的以字节为单位的,所以是要牵扯到大小端存储的~
以上面的例题为例:
小端存储:
大端存储:
比较12个字节是一样的,但是比较13个字节就会发现结果不一样了!
小端存储:
最后一个字节arr1中为04;arr2中为00;
arr1比arr2大~
大端存储:
最后一个字节arr1中为00;arr2中也为00;
arr1与arr2一样大~
模拟实现:
创建一个my_memcmp函数,模拟实现memcmp函数的功能:
int my_memcmp(const void* ptr1, const void* ptr2, size_t num)
{
assert(ptr1 && ptr2); //以上代码与前面的模拟函数类似,这里就不多赘述了
while (num--)
{
if (*(char*)ptr1 == *(char*)ptr2)
{
(char*)ptr1 += 1;
(char*)ptr2 += 1;
}
else
return *(char*)ptr1 - *(char*)ptr2;
}
return 0;
}
int main()
{
int arr1[] = { 1,2,3,4,5 };
int arr2[] = { 1,2,3,0,0 };
int ret = my_memcmp(arr1, arr2, 12);
printf("%d\n", ret);
return 0;
}
该函数与我这个系列的(二)号文章中的strncmp函数模拟原理几乎相同,只不过多了个强制类型转换,也不用判断'\0'
有兴趣的可以看看那篇文章:strn...类字符串函数详解及模拟实现
该函数也是分大小端区别的!
4. memset
memset函数的作用:修改内存信息
第一个参数是要修改的内存的起始位置;
第二个参数是要修改成为的内容;
第三个参数是要修改的字节数;
EX:
int main()
{
int arr[] = { 1,2,3,4 };
memset(arr, 1, 8);
int i = 0;
for (i = 0; i < 4; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
通过观察内存我们可以看到将arr起始的后八个字节的内容都改成了1
模拟实现:
创建一个my_memset函数,模拟实现memset函数的功能:
void* my_memset(void* ptr, int value, size_t num)
{
assert(ptr);
while (num--) //控制更改几个字节的内容
{
*(char*)ptr = (char)value; //强制类型转化为char*与char类型进行赋值,因为char类型占一个字节
(char*)ptr += 1; //强制类型转化为char*类型,+1,跳过一个字节的大小
}
}
int main()
{
int arr[] = { 1,2,3,4 };
my_memset(arr, 1, 8);
int i = 0;
for (i = 0; i < 4; i++)
{
printf("%d ", arr[i]);
}
return 0;
}