• 【C进阶】内存函数


     strcpy拷贝的仅仅是字符串,但是内存中的数据不仅仅是字符,所以就有了memcpy函数

    1. memcpy

    void *memcpy (void * destination ,const void * source , size_t num)

    函数memcpy从source的位置开始向后拷贝num个字节的数据到destination的内存位置

    1. #include
    2. int main()
    3. {
    4. int arr1[10] = { 0 };
    5. int arr2[] = { 1,2,3,4,5 };
    6. //把arr2中的前5个整形的数据,拷贝放到arr1中
    7. memcpy(arr1, arr2, 20);
    8. return 0;
    9. }

    可以看到前5个整形都拷贝过来了 


     memcpy函数的模拟实现:

    (1)一个字节一个字节的拷贝(dest,src转为char *

    eg:如果拷贝7个字节(两个int *类型指针不能操作)

    (2)(char *)dest++不能这样写,因为++的优先级高于强制类型转换

    相当于先对原类型进行++,再进行进行强转

    前置++(char *)dest虽然C语言中可以,但是改为c++就不能运行,所以还是正常写+1

    1. #include
    2. #include
    3. void* my_memcpy(void* dest, const void* src, size_t sz)
    4. {
    5. void * ret=dest;
    6. assert(dest && src);
    7. while (sz--)
    8. {
    9. *(char*)dest = *(char*)src;
    10. dest = (char*)dest + 1;
    11. src = (char*)src + 1;
    12. }
    13. return ret;
    14. }

    一个数组arr={1,2,3,4,5,6,7,8,9,10},如果想在自身的基础上进行拷贝,即把1,2,3,4,5拷贝到3,4,5,6,7的位置上,想得到结果:1,2,1,2,3,4,5,8,9,10

    但是得到的结果却是1 2 1 2 1 2 1 8 9 10

    我们就发现不重叠内存的拷贝,可以使用memcpy,

    重叠内存的拷贝,使用memmove函数

     上面其实是标准规定,但是实际在VS2022这个环境中,memcpy也能实现重叠内存的拷贝

    (其他平台不一定)

    1. #include
    2. #include
    3. #include
    4. void* my_memcpy(void* dest, const void* src, size_t sz)
    5. {
    6. assert(dest && src);
    7. while (sz--)
    8. {
    9. *(char*)dest = *(char*)src;
    10. dest = (char*)dest + 1;//这里不能写成(char*)dest++,强制类型转化是临时的,++的时候dest并不一定是char*类型的
    11. src = (char*)src + 1;
    12. }
    13. }
    14. int main()
    15. {
    16. int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
    17. my_memcpy(arr + 2, arr, 20);
    18. for (int i = 0; i < 10; i++)
    19. {
    20. printf("%d ", arr[i]);
    21. }
    22. return 0;
    23. }

     2. memmove

    void *memmove(void * destination ,const void * source , size_t num)

     参数和memcpy一样,但是memmove可以实现重叠内存的拷贝


     memmove函数的模拟实现:

    (这里不考虑直接开辟一个相同的空间再进行拷贝元素)

    讨论:

    dest

    dest>src:只能从后向前拷贝

    dest和src不相干的时候:从后往前或者从前往后都可以

    1. #include
    2. #include
    3. void* my_memmove(void* dest, const void* src, size_t sz)
    4. {
    5. void* ret = dest;
    6. assert(dest && src);
    7. if (dest < src)
    8. {
    9. //前->后
    10. while (sz--)
    11. {
    12. *(char*)dest = *(char*)src;
    13. dest = (char*)dest+1;
    14. src = (char*)src+1;
    15. }
    16. }
    17. else
    18. {
    19. //后->前
    20. while (sz--)
    21. {
    22. *((char*)dest + sz) = *((char*)src + sz);
    23. }
    24. }
    25. return ret;
    26. }
    27. int main()
    28. {
    29. int arr[20] = { 1,2,3,4,5,6,7,8,9,10 };
    30. my_memmove(arr , arr+2, 20);
    31. for (int i = 0; i < 10; i++)
    32. {
    33. printf("%d ", arr[i]);
    34. }
    35. return 0;
    36. }

    3. memcmp

    int memcmp ( const void * ptr1,const void *( ptr2  ,  size_t num )

     类似strcmp函数,memcmp是一对字节一对字节进行比较,比较num个字节ACSII值

    (1)返回值:

    • 如果返回值 < 0,则表示 str1 小于 str2
    • 如果返回值 > 0,则表示 str1 大于 str2
    • 如果返回值 = 0,则表示 str1 等于 str2
    1. #include
    2. #include
    3. int main()
    4. {
    5. int arr1[] = { 1,2,3,4,5,6,7 };
    6. //01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00 06 00 00 00 07 00 00 00
    7. int arr2[] = { 1,2,3,0x11223304 };
    8. //01 00 00 00 02 00 00 00 03 00 00 00 04 33 22 11
    9. int ret = memcmp(arr1, arr2, 13);
    10. printf("%d\n", ret);
    11. }

    上面这个代码虽然arr1的元素多,但是比较前13个字节的大小都一样,那么ret=0


    4. memset

    void *memset( void *dest, int c, size_t count

    复制字符c(一个无符号字符)到参数str所指向的字符串的前n个字符

    (初始化前count个字节为c)

    是以字节为单位设置内存的

    eg1:将hello world中的wor改为xxx:

    1. #include
    2. #include
    3. int main()
    4. {
    5. char arr[] = "hell0 world";
    6. memset(arr + 6, 'x', 3);
    7. printf("%s\n", arr);
    8. return 0;
    9. }

    eg2: 思考这个代码将arr改为了啥?

    1. #include
    2. #include
    3. int main()
    4. {
    5. int arr[10] = { 0 };
    6. memset(arr, 1, 40);
    7. return 0;
    8. }

    每一个int类型的元素的每一个字节都改为了1

    所以想把数组每一个元素都初始化为1,用memset函数是不可能实现的

    但是可以都初始化为0


    本次内容就到此啦,欢迎评论区或者私信交流,觉得笔者写的还可以,或者自己有些许收获的,麻烦铁汁们动动小手,给俺来个一键三连,万分感谢 ! 

  • 相关阅读:
    IMX6ULL | 从零开始移植uboot |(一)单板建立与编译
    Thales安全解决方案:国家网络安全的关键
    Nginx__基础入门篇
    vue3.0 01 项目的创建与setup组合式写法的基本使用 watch与watchEffect基本用法
    2007-2019年36家上市银行绿色信贷余额、绿色信贷占比、资产收益率、不良贷款率等数据
    【BUG】已解决:ModuleNotFoundError: No module named ‘cv2’
    【libGDX】初识libGDX
    《当代教育实践与教学研究》期刊简介及投稿要求
    选择器基础
    node.js中express框架cookie-parser包设置cookie的问题
  • 原文地址:https://blog.csdn.net/qq_73017178/article/details/133714745