【C】剖析C语言内存函数
前言:
上一篇文章详细介绍了字符串函数,那字符串函数和内存函数到底有什么区别呢?
最根本的区别在于,他们操作的对象不同,视角不同。
字符串函数针对的是一个个的字符,而内存函数顾名思义关注的是内存,存储在内存中的一个个字节。
一、memcpy函数
功能:
复制内存块,可以将任意类型的数据进行拷贝。
将source的num个字节的内容拷贝到destination内存中
参数和返回值:
前面两个参数分别是目标内存的起始地址和源内存的起始地址,第三个参数是需要拷贝内容的字节个数。
返回值是destination的首元素地址
头文件:
#include <string.h>
与strcpy的区别
- memcpy不需要考虑' '的问题,因为操作对象就是内存,视角不同
- memcpy可以拷贝任意类型的数据,而strcpy只能拷贝字符的数据
注意事项:
- 因为要接收任意类型的指针数据,所以函数参数类型就是void*
- 如果source和destination有任何的重叠,复制的结果都是未定义的,容易拷贝已经重叠的内容。
模拟实现:
char* my_memcpy(void* dest, const void* sou, size_t num)
{
void* ret = dest;
while (num--)
{
*(char*)dest = *(char*)sou;
//(char*)dest++;
dest = (char*)dest + 1;
sou = (char*)sou + 1;
}
return ret;
}
int main()
{
int arr1[20] = { 0 };
int arr2[] = { 1,2,3,4,5,6,7 };
my_memcpy(arr1, arr2, 21);
for (int i=0;i<10;i++)
{
printf("%d ", arr1[i]);
}
return 0;
}
灵魂总结:
- 如果函数的参数可以接收任意类型的数据,那么设置这种函数参数一般用void*。
- 如果函数可以对任意类型的数据进行改变,并且根据字节的个数来决定,那么函数参数的类型设置为char*。
二、memmove函数
功能:
与memcpy函数功能相似,但是memmove函数功能更强大,可以拷贝带有重叠的内存块,因此我们以后可以直接采用memmove函数去拷贝内容,不论是重叠或不重叠 。
TIP:memcpy和memmove的渊源:
为何memcpy函数拷贝重叠的字符串会有问题呢?
比如我们有这样的一段内存,然后soul为起始地址,传3个整型(12个字节)到dest位置上。
但是如果用memcpy拷贝的方法,发现已经先把1覆盖到了3的位置,所以3就变成了1,之后再想拷贝3发现已经被覆盖为1,所以此法不通。
解决方法:
我们可以从后向前拷贝,先将sou最后的3拷贝到dest最后的5,接着再向前拷贝,这样就避免了重叠的问题
新的问题:
还是一样的需求,把sou为起始地址,传3个整型(12个字节)到dest位置上。
但这时再从后向前拷贝,会将3重叠为5,之后再想拷贝3,就会变成5.
解决方法:
我们从前向后拷贝,从sou的3开始拷贝,这样也避免了重叠问题。
总结:
遇到不同的情况,我们采取不同的措施,分情况的标准就是sou,和dest的地址高低,若sou<dest,我们就采用从后向前拷贝,若sou>dest,我们就采用从前向后的拷贝方法。
模拟实现memmove函数
#include<assert.h>
void* my_memmove(void* dest, void* soul, size_t num)
{
void* ret = dest;
if (soul < dest)
{
dest = (char*)dest + num-1;//需要减去1,因为+1就是两个字节了
soul = (char*)soul + num-1;
while (num--)
{
*(char*)dest = *(char*)soul;
dest = (char*)dest - 1;
soul = (char*)soul - 1;
}
}
else
{
while (num--)
{
*(char*)dest = *(char*)soul;
dest = (char*)dest + 1;
soul = (char*)soul + 1;
}
}
return ret;
}
int main()
{
int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
my_memmove(arr1, arr1+2, 12);
for (int i=0;i<10;i++)
{
printf("%d ", arr1[i]);
}
return 0;
}
三、memcmp函数
功能:
两个指针指向的内容进行比较,并从起始位置往后的num个字节内容进行比较
参数和返回值:
参数为两个指针,并且加上限制字节的个数
返回值,如果前者大于后者,返回大于0的数字,如果前者小于后者,返回小于0的数字,两者相等,返回0。
注意:
- 可以比较任意类型的数据
- 比较的方式就是一个字节的内容和另一个字节的内容进行比较
四、memset函数
功能:
以字节为单位,将ptr指向的内容修改为num个字节的value值
实操:
上面是char类型,下面是int类型,int类型更便于我们理解
时时刻刻要想到内存函数操作的对象是字节,比如上面的整型例子,memset操作了10个字节,相当于把两个整型的内容改成01 01 01 01,然后第三个元素改成01 01 00 00