学习目标:
掌握使用规律,及部分模拟实现
对比前一篇文章的那些个字符串操作函数,提出内存操作函数,是为了挣脱前述内容仅能操作字符串的束缚。
学习内容:
1:memcpy
①:标准格式:void * memcpy ( void * destination, const void * source, size_t num );
②:含义:从source起拷,拷num个字节的内容,从destination起放。返回destination。
③:注意事项:
(a):该函数是针对底层数据的二进制副本,该函数不会去检查源字符串中的任何字符串结束标志,你给这个函数一个源地址,它总会从这开始精确的拷贝num个字节内容放到destination所指向的空间,所以说,目标空间和源空间都至少有num个字节内容才安全。
(b):目标空间和源空间不要有重叠的部分,若有重叠的部分建议使用更加安全的memmove函数,具体往下看。
④:使用案例:
#include <stdio.h>
#include <string.h>
struct stu
{
char name[50];
int age;
}s1;
int main()
{
char myname[] = "i am a good student";
memcpy(s1.name, myname, strlen(myname) + 1);
printf("%s\n", s1.name);
return 0;
}
⑤:模拟实现
#include <stdio.h>
void* my_memcpy(void* destination, const void* source, size_t num)
{
char* ret = (char*)destination;
int i = 0;
for (i = 0; i < num; i++)
{
*(char*)destination = *(char*)source;
destination = (char*)destination + 1;
source = (char*)source + 1;
}
return ret;
}
struct stu
{
char name[50];
int age;
}s1;
int main()
{
char myname[] = "i am a good student";
char*ret=my_memcpy(s1.name, myname, strlen(myname) + 1);
printf("%s\n", ret);
return 0;
}
⑥若非要在源空间和目标空间有重叠时使用memcpy会怎么样?
离谱的事情发生了!结果居然是在预料当中!,这其实是VS2019足够强大,那如果用我们自己模拟实现的那个代码去操作这个图片内容:
可以发现,非理想效果。代码摆在这,其实可以预想得到这个结果。如下:(其实memcpy就是周这么实现的,只不过它有优化的空间,可以防止源目有重叠情况的发生,且VS2019做到了,我们没做到)
2:memmove
①:格式:void * memmove ( void * destination, const void * source, size_t num );
②:含义:就是比memcpy多了一个适用范围,即:它可以允许我们在源空间和目标空间出现重叠时使用,它这样就像是使用了一个中间缓冲区一样的东西。同样的,该函数是不会检查源空间中的任何终止空字符的,所以说,使用时它总是精准的赋值num个字节的内容,你只不过是给它一个起点而已。为了避免溢出,目标空间和源空间内容不得少于num个字节的内容哦。
③:使用案例:
④:memmove的模拟实现
先理解一下思想:在这先给一个arr[]={1,2,3,4,5,6,7,8,9,10};
通过上述的理解,是不是该明白: 有重叠空间的memcpy或者说memmove去模拟实现的话,可不可以总结成这样:对source:把前面的数据拿到后面,那对source来说,就从后面开始拷贝,逐个往前一个个拷贝,然后放到destination,反之则反。
#include <stdio.h>
void* my_memmove(void* destination, const void* source, size_t num)
{
void* ret = destination;
if (destination > source)//source中的数据往后拿,拷贝顺序是从后往前
{
while (num--)
{
*((char*)destination+num) = *((char*)source+num);
}
}
else//source中的数据往前拿,拷贝顺序是从前往后
{
while (num--)
{
*(char*)destination = *(char*)source;
destination = (char*)destination + 1;
source = (char*)source + 1;
}
}
return ret;
}
int main()
{
int arr[] = {1,2,3,4,5,6,7,8,9,10};
my_memmove(arr + 2, arr, 16);
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
3:memcmp
①:格式:int memcmp ( const void * ptr1, const void * ptr2, size_t num );
②:含义:从ptr1和ptr2开始,逐一比对字节数据是否一致,不一致返回非零,一致则返回0
③:使用案例:
#include <stdio.h>
#include <string.h>
int main()
{
int arr1[] = {1,2,3,4,5};//小端:01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00
int arr2[] = {1,2,3,5,4};//小端:01 00 00 00 02 00 00 00 03 00 00 00 05 00 00 00 04 00 00 00
int ret=memcmp(arr1, arr2, 13);
printf("%d\n", ret);
return 0;
}
4:memset
①:格式:void * memset ( void * ptr, int value, size_t num );
②:含义:将ptr指向的内存块的前num个字节设置为指定值(解释为unsigned char)。
③:使用案例:
5:补充:strerror
①:格式:char * strerror ( int errnum );
②:含义:errnum为错误码,给strerror一个错误码,它就给你这个错误码所对应的错误信息(字符串)。
③:使用案例:
6:perror
①格式:void perror ( const char * str );
②:含义:先以%s打印str,然后跟一个冒号一个空格,再接一个strerror的功能!并且,str是否为NULL都不影响错误报告的打印并\n
③:使用案例:
上述仅供参考
学习时间:
2021.10
学习产出:
1、 技术笔记 2 遍
2、CSDN 技术博客 1 篇
3、 gitee