网站移动端生成器,照片墙网站源码,苏州 中英文网站建设,孝义网站开发1 memcpy的使用和模拟实现
紧接字符串函数#xff0c;出场的是第一个内存函数memcpy。前面讲的字符串函数是专门干关于字符串的事的#xff0c;而这个函数可以干strcpy一样的事#xff0c;但是区别就是它碰到\0也会继续复制。 函数的头文件是string#xff0c;返回类型是v…1 memcpy的使用和模拟实现
紧接字符串函数出场的是第一个内存函数memcpy。前面讲的字符串函数是专门干关于字符串的事的而这个函数可以干strcpy一样的事但是区别就是它碰到\0也会继续复制。 函数的头文件是string返回类型是void*参数有两个一个是目的地地址一个是源的地址还有一个是整型这个整型代表的是要复制多少个字节返回值是目的地的地址因为源的值是不能被修改的所以用const修饰因为参数是void*所以在一会儿模拟实现的时候我们就要强制转化成char*的毕竟是修改字节。
先看一段简单的代码。
int main()
{int arr1[10] { 1,2,9,4,5,6,7,8,9,10 };int arr2[10] { 0 };memcpy(arr2, arr1[4], 9);for (int i 0; i 10; i){printf(%d , arr2[i]);}return 0;
}这串代码的意思就是从arr1[4]开始给arr2复制复制9个字节还是很好理解的那如果不是在一个空间呢比如我把arr1[4]的位置给arr1开始复制会不会报错呢答案是可能会。
如果目的地和源的内存有任何重叠的话复制的结果都是未定义的也就是说mencpy的行为是不可预测的咱也不知道它会干啥像这样。
int main()
{char str[] Hello, World!;memcpy(str 7, str, 7);printf(%s\n, str);return 0;
}结果是未知的所以重叠的部分就不应该用mencpy了。
好了我们现在就模拟实现一下memcpy函数。
主函数开始传两个地址和一个整型过去因为复制的是字节所以我们可以使用字节数当作循环变量for while循环都可以因为参数都是泛型指针所以有必要强制转化为char*指针转化之后就是复制了这里有个需要注意的点就是不能直接*(char*)p1这样系统会报错的我们就可以换一个思路如下。
当然返回的地址需要用一个临时变量存起来最后返回就行了因为返回的是泛型指针所以临时变量的指针类型也是void*。
void my_memcpy(void* p2, const void* p1, size_t num)
{void* ret p2;for ( ; num 0; num--){*(char*)p2 *(char*)p1;(char*)p2 (char*)p2 1;(char*)p1 (char*)p1 1;}return ret;
}
int main()
{srand((unsigned int)time(NULL));int arr1[10] { 1,2,9,4,5,6,7,8,9,10 };int arr2[10] { 0 };int num rand() % 40 1;my_memcpy(arr2, arr1, num);for (int i 0; i 10; i){printf(%d , arr2[i]);}return 0;
}
读者可以自行实验一下。 2 memmove的使用和模拟实现
memcpy是不能让同一块空间复制的但是menmove就可以它和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
先上代码实验一下。
int main()
{char arr[] Hello world!;memmove(arr, arr 1, 3);printf(%s, arr);return 0;
}
最后的结果就是elllo world!内存重叠了在memmove这里是没有任何问题的但是在vs里面尝试对重叠的空间使用memcpy可能是不会报错的这与vs有关我们先不用在意。
现在讨论模拟实现memmove。
我们首先想为什么使用内存函数需要考虑空间是否重叠这是因为如果重叠了就会导致内存复制的时候复制过去上一次复制留下的元素那么解决方案是什么是单独拿一块空间出来存储要存放的元素吗这个实际上可以但是不免会浪费挺多空间。较好的办法就是改变复制的顺序如下。 假定红色区域是来源绿色和蓝色部分是目的地均有重叠因为重叠无非就是前面重叠或者是后面重叠所以有两种情况
第一种情况绿色情况假如从前往后复制即从5开始复制是没有问题的因为重叠部分5复制的时候9没有发生改变如果是从后往前复制即从9开始复制那么最后复制5的时候5已经发生了改变复制就会出错。
第二种情况蓝色情况假如从前往后复制即从5开始复制那么在复制13那个位置的时候。9已经发生了改变变成了5所以复制会出错同理后往前复制就不会出错。
可以总结一个小规律复制的方向取决于重叠的部分只需要保证在复制的时候重叠的部分还没有被复制就行所以一共就两种情况。
void my_memmove(void* p1, const void* p2, size_t num)
{void* ret p2;if (p1 p2)//前往后{while (num){*(char*)p1 *(char*)p2;(char*)p1 (char*)p1 1;(char*)p2 (char*)p2 1;num--;}}else//后往前{(char*)p2 (char*)p2 num - 1;(char*)p1 (char*)p1 num - 1;while (num){*(char*)p1 *(char*)p2;(char*)p1 (char*)p1 - 1;(char*)p2 (char*)p2 - 1;num--;}}return ret;
}
int main()
{char str1[100] Hello world!;//Hehellworldmy_memmove(str1 2, str1, 4);printf(%s, str1);return 0;
}
我们讨论的就是传过去的地址的大小是谁高如果目的地的地址高于来源的地址那么复制的方向就是从前往后如果低于那么复制的地址就是从后往前。特别要注意的是第二种情况如果是从后往前那么两个指针指向的位置都需要发生改变所以需要先加上复制的字节数。第二种情况下容易犯错的是指向的位置应该加字节数在建减一个1这点可以自行实验一下。
memmove函数模拟实现就完成了。
可以这样理解
memcpy可以实现的memmove都可以实现唯一的区别只是内存空间不能重叠的问题。 3 memset的使用和模拟实现 在cplusplus中memset的返回值void*返回的是传进去的地址参数有三个泛型指针存进去的值设置的字节数。
这个函数的功能就是把内存中的值设置成自己想要的值那有人问了为什么第二个参数是int类型的这是因为字符在计算机中实际上是以AscII值的形式读取的所以参数类型是int类型。
int main()
{char arr1[100] abcdefg;memset(arr1,*,6);printf(%s, arr1);return 0;
}
这是一个简单应用那么现在模拟实现一下模拟实现难度不大每个字节设置一下就行了。
void* my_memset(void* p1, int tem, size_t num)
{void* ret p1;while (num--){*(char*)p1 tem;(char*)p1 (char*)p1 1;}return ret;
}
int main()
{char arr1[100] abcdefg;my_memset(arr1, *, 3);printf(%s, arr1);return 0;
} 4 memcmp的使用和模拟实现 根据cplusplusmemcmp的返回值是int类型的实际上和strcmp一样返回的值就是1 0 -1strcmp是用来比较字符串的memcmp就是用来比较内存的比较的每个字节每个字节的比较的。
头文件还是string参数有3个分别是两块内存的地址和比较的字节数的大小话不多说看看简单的使用。
int main()
{char str1[100] abCdefg;char str2[100] abcdefg;int ret1 memcmp(str1,str2,3);int ret2 memcmp(str2, str1, 3);int ret3 memcmp(str1, str2, 2);printf(%d\n, ret1);printf(%d\n, ret2);printf(%d\n, ret3);return 0;
} 所以字符串函数能做到的许多内存函数也是可以做到的模拟实现和strcmp很是相似这里就不模拟实现了重点是memmove的使用和模拟实现。 感谢阅读