C语言内存函数
memcpy
使用和模拟实现
memcpy
使用
c
void* memcpy(void* destination(目标),const void* source(源头),size_t num(字节));
memcpy会把source指向位置的内容拷贝到destination指向内存的位置,拷贝大小是num个字节 ,注意在正常拷贝的过程中,memcpy
函数遇到\0并不会停止 ,而是在拷贝目标字节数之后停止,即会将\0一同拷贝到目标位置
例如:
将数组arr1在的数据拷贝到数组arr2中
c
#include<stdio.h>
#include<string.h>
int main()
{
int arr1[5] = {1,2,3};
int arr2[5] = { 0 };
int i = 0;
memcpy(arr2, arr1, 20);
for(i = 0; i< 5;i++)
{
printf("%d ",arr2[i]);
}
return 0;
}
memcpy
模拟实现
在模拟实现 memcpy
函数的功能时,我们要了解,该函数时是内存拷贝,对于内存拷贝有以下解释:
内存拷贝:只关注要拷贝的数据在哪里,要存放到哪里,拷贝几个字节,至于内存中存放什么数据,什么类型的数据,都不重要
通常使用memcpy
函数拷贝不重叠的内存的数据,memcpy
函数不保证重叠内存的拷贝,而对重叠内存的拷贝使用memmove
既然是内存拷贝,那么我们事先就不知道要拷贝数据的类型,所以我们使用了void*来表明指针dest和src所指向数据的不确定性,我们可以想到,char类型的数据在存储时,是只占用一个字节的,那么我们就可以用一个循环,逐字节的拷贝数据,而我们在拷贝的过程中要使用指针,所以需要assert断言指针不为NULL
分析好之后,下面呢就是具体的模拟实现操作
c
#include<stdio.h>
#include<string.h>
#include<assert.h>
void* my_memcpy(void* dest,const void* src,size_t num)
{
void* ret = dest;
assert(dest && src);
while (num--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
return ret;
}
int main()
{
int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[10] = { 0 };
my_memcpy(arr2,arr1,20);
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d " ,arr2[i]);
}
return 0;
}
memmove
的使用和模拟实现
c
void* memmove ( void* destination, const void* source, size_t num );
上面我们提到,memmove
函数能够实现重叠内存的拷贝,那究竟是怎么做到的呢?其实是因为在拷贝之前,我们进行了判断,判断在拷贝时是从前向后拷贝,还是从后向前拷贝,这样我们可以很好的解决内存重叠的问题
看着图片我们可以很直观的分析,
假设我们将2345所处位置的内容拷贝到3456中,如果我们从前向后拷贝的话,2变成3,那原来位置的3就已经被拷贝成了2,我们想要将3拷贝到4位置的时候,从原来3的位置取出的就变成了2,以此类推,其余的结果也发生了偏差
这种情况是我们不想看到的,其实解决方法也很简单,只需要将2345的内容从后向前拷贝就可以了。
反之如果我们想要将3456的内容拷贝到2345中,只需要从前向后拷贝就可以了
接下来是模拟实现
c
#include<stdio.h>
#include<string.h>
#include<assert.h>
void* my_memmove(void* dest, void* src, int n)
{
void* ret = dest;
assert(dest && src);
//当源头在目标空间右边时,从前向后拷贝
//(char*)dest >= ((char*)src + n)这段代码是说当src与dest没有重叠时,任何拷贝 //方式都可以
if (dest <= src || (char*)dest >= ((char*)src + n))
{
while (n--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
}
//当源头在目标空间左边时,从后向前拷贝
else
{
dest = (char*)dest + n - 1;
src = (char*)src + n - 1;
while (n--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest - 1;
src = (char*)src - 1;
}
}
return ret;
}
int main()
{
int str1[10] = { 1,2,3,4,5,6,7,8,9,0 };
int str2[20] = { 0 };
my_memmove(str1+4, str1, 20);
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", str1[i]);
}
return 0;
}
memset
的使用
c
void * memset ( void * ptr, int value, size_t num(字节) );
memset
是⽤来设置内存的,将内存中的值以字节为单位设置成想要的内容。
c
#include <stdio.h>
#include <string.h>
int main ()
{
char str[] = "hello world";
memset (str,'x',6);
printf(str);
return 0;
}
memset
功能效果图:
memcmp
的使用
c
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
用来比较两个内存块的
⽐较从ptr1和ptr2指针指向的位置开始,向后的num个字节
返回值
如果pstr1指向的字符串大于pstr2指向的字符串,那么返回大于0的数
如果等于,返回0
如果小于,返回小于0的数(大多数编译器常为-1)
memcmp
模拟实现
c
#include<stdio.h>
#include<string.h>
#include<assert.h>
int my_memcmp(const void* str1, const void* str2, size_t n)
{
assert(str1 && str2);
while ((char*)str1 == (char*)str2)
{
if ((char*)str1 == '\0')
{
return 0;
}
(char*)str1 = (char*)str1+1;
(char*)str2 = (char*)str2+1;
}
return (char*)str1-(char*)str2;
}
int main()
{
char str1[] = "siohoewgh23fk5";
char str2[] = "siohoewgh23fk4sjica";
int n = memcmp(str1, str2, sizeof(str1));
if (n > 0)
{
printf("str1>str2");
}
else if (n < 0)
{
printf("str1<str2");
}
else
{
printf("str1=str2");
}
return 0;
}