zoukankan      html  css  js  c++  java
  • 使用memcpy函数时要注意拷贝数据的长度

    memcpy函数简介

    memcpy函数是C/C++语言中的一个用于内存复制的函数,声明在 string.h 中(C++是 cstring)。其原型是:

    void *memcpy(void *destin, void *source, unsigned n);
    

    作用是:以source指向的地址为起点,将连续的n个字节数据,复制到以destin指向的地址为起点的内存中。
    函数有三个参数,第一个是目标地址,第二个是源地址,第三个是数据长度。
    使用memcpy函数时,需要注意:

    • 数据长度(第三个参数)的单位是字节(1byte = 8bit)。
    • 注意该函数有一个返回值,类型是void*,是一个指向destin的指针。

    memcpy函数复制的数据长度

    使用memcpy函数时,特别要注意数据长度。
    如果复制的数据类型是char,那么数据长度就等于元素的个数。而如果数据类型是其他(如int, double, 自定义结构体等),就要特别注意数据长度的值。
    好的习惯是,无论拷贝何种数据类型,都用 n * sizeof(type_name)的写法。
    先以最简单的情况说明:

        char a[10] = "abcdefgh";
        unsigned n = 2;
        void * p = memcpy(a+3, a, n);
    

    以上代码将从a开始的两个字节的数据(即'a'和'b'),复制到从a+3开始的内存('d'所在的地址)。这样,'d'和'e'被替换。
    执行结束之后,字符数组(字符串)a的内容变为"abcabfgh",返回值p即为a的地址(p == a)。

    再以int类型为例说明:

        int a[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
        unsigned n = 5;
        void * p = memcpy(a+3, a, n);
    

    int类型的长度是4个字节。以上代码将从a开始的5个字节的数据复制。5个字节的数据是什么呢?前四个字节组成了一个完整的int(即第一个元素0)。第五个字节,只能取到第二个元素的第1个字节。这里又会涉及到big-endian和little-endian的问题。假设是小端方式储存(更常见),那么读到的是元素1的低8位,写成十六进制即0x1
    目标地址是a+3。由于指针加减常数,单位是与类型保持一致的,也就是在a的基础上,增加3倍int长度,对应的是元素3的地址。元素3被替换为0。元素4写成十六进制是0x0004,低8位被替换为0x1,变为0x0001
    所以执行结束之后,数组a的内容变为 { 0, 1, 2, 0, 1, 5, 6, 7, 8, 9 },返回值p即为a的地址(p == a)。
    根据上面的解释,如果把程序里的n改为6、7、8,那么结果都是一样的。因为数字1和4的二进制表示除了低8位不同,高位都是0。

    倘若高位不相同,那么结果就没那么简单了。还是以int数组为例:

        int a[10] = { 0, -1, 2, 3, 4, 5, 6, 7, 8, 9 };
        unsigned n = 5;
        memcpy(a+3, a, n);
    

    复制5个字节的数据,前4个字节组成了一个int,即第一个元素0。那么元素3被替换为0。第5个字节从-1中取。-1的十六进制表示为0xFFFF,第5个字节的数据是0xF。元素4变为0x000F,即15。数组a变为 { 0, -1, 2, 0, 15, 5, 6, 7, 8, 9 }。
    如果 n = 6,那么4变为```0x00FF``,即255。数组a变为 { 0, -1, 2, 0, 255, 5, 6, 7, 8, 9 }。

    可以看出,如果你想用memcpy复制元素,那么一定要写对数据长度。如果要完整地复制 n 个 int 类型元素,那么写法如下:

        int a[10] = { 0, -1, 2, 3, 4, 5, 6, 7, 8, 9 };
        unsigned n = 5 * sizeof(int);
        memcpy(a+3, a, n);
    

    数组a变为 { 0, -1, 2, 0, -1, 2, 0, -1, 8, 9 }。
    如果是其他类型,用法也是一样的。

    好的习惯是,如果拷贝何种数据类型,都用 n * sizeof(type_name)的写法。

  • 相关阅读:
    在安卓上用Termux安装sqlmap
    地址转换函数
    字节操作函数
    主机字节序和网络字节序
    20191231 Spring官方文档(Core 1.13-1.14)
    20191230 Spring官方文档(Core 1.12)
    20191230 Tomcat权威指南-读书摘要系列【归档】
    20191230 On Java8【归档】
    20191227 Java8 日期时间API
    20191226 Spring官方文档(Core 1.11)
  • 原文地址:https://www.cnblogs.com/xia-weiwen/p/11255927.html
Copyright © 2011-2022 走看看