⭐博客主页:️CS semi主页
⭐欢迎关注:点赞收藏+留言
⭐系列专栏:C语言进阶
⭐代码仓库:C Advanced
家人们更新不易,你们的点赞和关注对我而言十分重要,友友们麻烦多多点赞+关注,你们的支持是我创作最大的动力,欢迎友友们私信提问,家人们不要忘记点赞收藏+关注哦!!!
在之前讲解的关于字符串的拷贝我们已经知道了strcpy,strcmp,strstr等的处理字符串的库函数,但是现在有一个情况了,倘若是数字数组呢?数字字符进行拷贝,移动和比较是不是没有办法,对,这种方法叫做内存函数,所以今天我们要介绍的是memcpy,memmove,memcmp,memset这四个内存函数,对数组是很友好的!
根据图片我们能知道我们是根据字节的大小去决定拷贝过去的数,拷贝的方法是从src拷贝到dest中去。
我们先简单使用一下,如下代码:
#include
#include
int main() {
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[10] = { 0 };
memcpy(arr2, arr1, 20);
return 0;
}
那当然了,如果你想拷贝从3开始往后拷贝4个数(20个字节)的话那我们就直接变值即可,如下代码:
#include
#include
int main() {
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[10] = { 0 };
memcpy(arr2, arr1 + 2, 20);
return 0;
}
那我们拷贝17个字节呢?能不能拷贝过去呢?答案是可以的,可是发现下面的数据怎么拷贝了3,4,5,6,7过去呢?因为是数据在计算机中存放的是01 00 00 00小端存放,一直到7的位置存放的是07 00 00 00,所以取到了07,所以7能输出。
那解释后上完整代码(后面赋代码):
根据画图我们知道,当我们想拷贝过去的时候,我们并不知道这个指针是什么类型的,是整型?是字符?那不确定我们看着个传参过去的是字节大小,所以我们就想到了强制类型转换成为char*指针一个字节一个字节往后找即可。
#include
#include
//所以用void*
void* my_memcpy(void* dest, const void* src, size_t num) {
assert(dest && src);
//保存首元素地址
void* ret = dest;
while (num--) {
//不知道是什么类型的指针,那就来char*一个字节一个字节去拷贝即可
//一次强转是临时的
*(char*)dest = *(char*)src;
//强制类型转换
dest = (char*)dest + 1;
src = (char*)src + 1;
/*++(char*)dest;
++(char*)src;*/
}
return ret;
}
int main() {
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[10] = { 0 };
//不确定arr2和arr1里面是什么类型的指针
my_memcpy(arr2, arr1 + 2, 17);
return 0;
}
那我们就有个比较大胆的想法,我们能不能实现一下在自身字符串处移动,我们按照原本的套路试一下:
#include
#include
//所以用void*
void* my_memcpy(void* dest, const void* src, size_t num) {
assert(dest && src);
//保存首元素地址
void* ret = dest;
while (num--) {
//不知道是什么类型的指针,那就来char*一个字节一个字节去拷贝即可
//一次强转是临时的
*(char*)dest = *(char*)src;
//强制类型转换
dest = (char*)dest + 1;
src = (char*)src + 1;
/*++(char*)dest;
++(char*)src;*/
}
return ret;
}
void test1() {
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[10] = { 0 };
//不确定arr2和arr1里面是什么类型的指针
my_memcpy(arr2, arr1 + 2, 17);
}
void test2() {
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
my_memcpy(arr + 2, arr, 20);
}
int main() {
//test1();
test2();
return 0;
}
我们发现test2()函数看的样子很正确,可是真的这样吗?我们进入调试看一看吧!
这输出结果怎么是1 2 1 2 1 2 1 8 9 10,跟我们的预期结果1 2 1 2 3 4 5 8 9 10怎么差别那么大呢?我们画图解释一下:
发现当我们想要找替换3的时候,3已经被1覆盖了,只能复制1了,所以是错误的,那这种情况我们需要分情况讨论了:
以下情况是重叠的情况:
情况一:dest(被拷贝的数据)指针在src(源头数据)指针的左边时,需要从左往右拷贝,也就是从前往后拷贝。
情况二:dest(被拷贝的数据)指针在src(源头数据)指针的右边时,需要从右往左拷贝,也就是从后往前拷贝。
不重叠情况:从前往后拷贝和从后往前拷贝都可以。
那这么复杂的情况,早期的计算机编程师肯定想到过,所以就另外制作了一个库函数memmove来解决这种情况,那我们接下来介绍一下memmove库函数吧!
首先的首先我们,先看一下这个函数在MSDN的介绍:
有了上面的概念和我们需要进行移动的想法,我们直接用memmove实现一下吧:
上面两串代码就是memmove的魅力,不管是从前往后还是从后往前,memmove都可以进行移动。
既然有了上面的思路,那我们模拟实现就很轻松了,只要是dest在src左边的时候,那就是统一从前往后拷贝;dest在src右边的时候,那就是统一从后往前拷贝,注意,这里的dest和src是头指针:
#include
#include
void* my_memmove(void* dest, const void* src, size_t num) {
assert(dest && src);
//保存首元素地址
void* ret = dest;
if (dest < src) {
//从前向后拷贝
while (num--) {
//不知道是什么类型的指针,那就来char*一个字节一个字节去拷贝即可
//一次强转是临时的
*(char*)dest = *(char*)src;
//强制类型转换
dest = (char*)dest + 1;
src = (char*)src + 1;
/*++(char*)dest;
++(char*)src;*/
}
}
else {
//从后向前拷贝
while (num--) {
//第一次往后跳了19个字节
*((char*)dest + num) = *((char*)src + num);
}
}
return ret;
}
void test3() {
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
my_memmove(arr, arr + 2, 20);
}
int main() {
//test1();
//test2();
test3();
return 0;
}
我们先看一下MSDN的介绍:
即;比较从ptr1和ptr2指针开始的num个字节。
那我们根据介绍进行制作一下这个吧!
如图所示,当我们在进行比较的时候,是根据字节大小比较的,所以这就取决于编译器是大端还是小端,根据字节在内存中的存放顺序进行比较的,我们知道,在VS环境下,是小端存储,也就是说5是0x05 00 00 00,03是0x03 00 00 00,所以取第一个字节,较大的是05,所以当字节数为不是4的倍数的时候,我们也可以比较:
#include
#include
int my_memcmp(const void* buf1, const void* buf2, size_t count)
{
assert(buf1 && buf2);
//往后找字节进行比较
while (count--) {
if (*(char*)buf1 > *(char*)buf2) {
return 1;
}
else if (*(char*)buf1 < *(char*)buf2) {
return -1;
}
buf1 = (char*)buf1 + 1;//往后移动
buf2 = (char*)buf2 + 1;
}
return 0;
}
int main() {
int arr1[] = { 1,2,3 };
int arr2[] = { 1,2,5 };
int ret = my_memcmp(arr1, arr2, 9);
printf("%d\n", ret);
return 0;
}
名为内存设置函数,是以字节为单位来设置内存中的数据的。
如下所示,根据MSDN介绍我们进行书写:
#include
#include
void* my_memset(void* dest, int c, size_t count)
{
assert(dest);
//头指针给存起来
void* start = dest;
//循环相赋值
while (count--) {
*(char*)dest = (char)c;
dest = (char*)dest + 1;
}
return start;
}
int main()
{
char arr[] = "hello world!";
char* ret = my_memset(arr, 'x', 5);
printf("%s\n", arr);
return 0;
}
当我们使用这些函数的时候,我们需要搞清楚这些函数的传参以及我们需要注意的事情,尤其是我们需要熟悉并掌握模拟实现这些内存函数的使用,这个是很关键的,对于自己是有很大的提升的!!!
客官,码字不易,来个三连支持一下吧!!!关注我不迷路!!!