C语言全部内存操作函数的实现详细讲解
memcpy内存拷贝函数
void*memcpy(void*destination,constvoid*source,size_tnum);
- memcpy函数从source的位置开始向后拷贝num个字节的数据到destination的内存位置
- 这个函数在遇到\0的时候并不会停下来
- 如果source和destination有任何的重叠,复制的结果都是未定义的
使用方法:
#define_CRT_SECURE_NO_WARNINGS1 #include#include intmain() { chararr1[20]={0}; chararr2[]="helloworld!"; intarr3[10]={0}; intarr4[]={1,2,3,4,5,6,7,8,9,10}; inti=0; memcpy(arr1,arr2,12); memcpy(arr3,arr4,16); printf("%s\n",arr1); for(i=0;i<10;i++) { printf("%d",arr3[i]); } return0; }
如果源头和目的地是同一块内存它进行拷贝的时候会出现覆盖的情况。
如:
#include#include intmain() { intarr[]={1,2,3,4,5,6,7,8,9,10}; inti=0; memcpy(arr+2,arr,16); for(i=0;i<10;i++) { printf("%d",arr[i]); } return0; }
可以看到它并没有如我们预期的输出来输出结果,我们预期的结果应该是:12123478910
可是memcpy拷贝的时候会覆盖,而C语言对memcpy的标准是只要能实现拷贝即可,不考虑同一块内存拷贝会覆盖的情况,这种情况是由另一个函数来处理。
当然有些编译器对memcpy函数的实现是有优化过的,目前我个人知道的编译器是VS它是对memcpy有优化的,如果拷贝的是同一块内存它不会覆盖,而是如预期的那样进行拷贝。
memcpy函数的实现
#includevoid*my_memcpy(void*dest,constvoid*src,unsignedintcount) { assert(dest&&src);//断言 void*temp=dest;//temp保存dest的起始地址 while(count--) { *(char*)dest=*(char*)src;//复制src的内容到dest ++(char*)dest;//下一个字节的拷贝 ++(char*)src; } returntemp;//返回dest起始地址 }
void*my_memcpy(void*dest,constvoid*src,unsignedintcount);
参数一:void*dest
- dest设置成空类型,因为空类型可以接收任何大小的数据,但是有一个缺陷它不能自增或者自减,也不能直接解引用因给它空类型是一个没有具体类型,它不知道它能访问多少个字节,所以使用空类型的时候我们需要强制类型转换。
- dest是缓冲区
参数二:void*src
- 它的类型和dest一样不过,它和参数一不同的是它被const保护起来了,因为它只是被复制也就是说我们只是访问它里面的内容并不需要修改它,所以我们就加一个const把它保护起来,防止我们不小心对它进行修改
参数三:unsignedintcounst
- counst是我们要修改多少字节的参数,修改是以字节为单位的,它的类型是unsignedint(无符号整整形)也就是说不能出现负数
返回类型:void*
- 返回dest的首地址
assert(dest&&src)这个是用来保证代码的健壮性,assert()函数是断言,如果传过来的是空指针,那么就是假因为NULL的值是0,只有两边都为真才不会有提示。
*(char*)dest=*(char*)src因为是void*类型所以我们要强制转换才能解引用进行拷贝操作,而我们要操作的是一个字节所以转为字符型指针最合适。
++(char*)dest;和上面的同理,要强制类型转换才能进行++和–操作。
memmvoe函数
void*memmove(void*destination,constvoid*source,size_tnum);
- 和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
- 如果源空间和目标空间出现重叠,就得使用memmove函数处理
使用方法:
#define_CRT_SECURE_NO_WARNINGS1 #include#include #include intmain() { intarr[]={1,2,3,4,5,6,7,8,9,10}; inti=0; memmove(arr+2,arr,16); for(i=0;i<10;i++) { printf("%d",arr[i]); } return0; }
memmove和memcpy的使用方法一样,没什么大区别。
memmove函数的实现
#includevoid*my_memmove(void*dest,constvoid*src,unsignedintcount) { assert(dest&&src);//断言 void*temp=dest; if(dest 为了处理同块内存的拷贝,这里我们分为了两种方法。
- 从前向后拷贝
- 从后向后拷贝
memcpy用的是从前向后拷贝,所以会出现被覆盖的情况。
那么问题来了,我们什么情况才从前向后拷贝和从后向前拷贝呢?
我们可以以src为分界线,如果dest小于src我们就从前向后,这样就避免了src的内容被覆盖之后被拷贝到dest里面去,如果dest大于src,我们就从后向前。
那有人问如果等于呢?等于的话你从前向后还是从后向前不都一样?
所以按照这个思路我们写成两个拷贝顺序,从后向前我们不用思考了,想在我们只需要思考从后向前拷贝。
while(count--) { *((char*)dest+count)=*((char*)src+count); }从后向前我们只需要先得到dest和src末尾的地址就能进行从后向前操作了,count+dest不就得到了末尾了吗?counst+dest得到末尾的\0的地址,但是我们不需要修改\0所以count+dest之前我们对count自减。
后面就不需要dest自减的操作了,因为count每次减一我们就得到前面一个的地址,当count减完了,我们也拷贝完了。
memcmp内存块比较函数
intmemcmp(constvoid*ptr1,constvoid*ptr2,size_tnum);
- 比较从ptr1和ptr2指针开始的num个字节
- 返回值,当ptr1大于ptr2就返回大于1的值,当ptr1小于ptr2就返回小于0的值,当等于的时候返回0
使用案列:
#define_CRT_SECURE_NO_WARNINGS1 #include#include #include intmain() { chararr1[]="abcz"; chararr2[]="abcd"; if(0 memcmp(arr1,arr2,4)) { printf("小于\n"); } else { printf("等于\n"); } return0; } memcpy函数的实现
#includeintmy_memcmp(void*dest,constvoid*src,unsignedintcount) { assert(dest&&src);//断言 if(!count) { return0; } while(--count&&*(char*)dest==*(char*)src) { ++(char*)dest; ++(char*)src; } return*(char*)dest-*(char*)src; } if(!count) { return0; }如果count是0的话就直接返回0
while(count--&&*(char*)dest==*(char*)src) { ++(char*)dest; ++(char*)src; }当count个数比较完或者dest不等于src,我们就停止循环。
return*(char*)dest-*(char*)src;直接返回dest-src,如果它们两相等一定返回0,dest小于src返回的是小于0的值,大于则返回大于0的值。
memset修改内存块
void*memset(void*dest,intc,size_tcount)
- dest是目的
- 地第二个修改成什么?
- 第三个修改内存的个数
memset是以1字节为单位来修改,第二个参数是要修改成什么字符,第三个参数是修改内存个数以1字节为单位
使用案列:
#define_CRT_SECURE_NO_WARNINGS1 #include#include intmain() { chararr[10]={0}; inti=0; memset(arr,'6',10); for(i=0;i<10;i++) { printf("arr[%d]=%c\n",i,arr[i]); } return0; }
memset函数实现
#includevoid*my_memset(void*dest,inta,unsignedintcount) { assert(dest);//断言 void*temp=dest;//记录dest的首地址 while(count--) { *(char*)dest=a; ++(char*)dest; } returntemp;//返回dest的首地址 } while(count--) { *(char*)dest=a; ++(char*)dest; }把a的值给dest,来进行修改,每次修改一个字节就自增一修改下个字节。
到此这篇关于C语言全部内存操作函数的实现详细讲解的文章就介绍到这了,更多相关C语言内存操作函数的实现内容请搜索毛票票以前的文章或继续浏览下面的相关文章希望大家以后多多支持毛票票!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。