memcpy 函数

本文详细介绍了C/C++语言中的memcpy函数,包括其语法、工作原理及使用注意事项。通过具体实例展示了如何正确设置复制长度以避免数据错误。

原理

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

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

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

使用memcpy函数时,需要注意:

  • 数据长度(第三个参数)的单位是字节(1byte = 8bit)。
  • 注意该函数有一个返回值,类型是void*,是一个指向destin的指针。
void *memcpy(void *dst, const void *src, size_t size)
{
    char *psrc;
    char *pdst;

    if (NULL == dst || NULL == src)
    {
        return NULL;
    }

    if ((src < dst) && (char *)src + size > (char *)dst) // 出现地址重叠的情况,自后向前拷贝
    {
        psrc = (char *)src + size - 1;
        pdst = (char *)dst + size - 1;
        while (size--)
        {
            *pdst-- = *psrc--;
        }
    }
    else
    {
        psrc = (char *)src;
        pdst = (char *)dst;
        while (size--)
        {
            *pdst++ = *psrc++;
        }
    }

    return dst;
}

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 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 }。
如果是其他类型,用法也是一样的。

06-17
### memcpy 函数的使用方法及示例 `memcpy` 是 C/C++ 标准库中的一个函数,用于将一块内存的内容复制到另一块内存中。以下是关于 `memcpy` 的详细信息和使用示例。 #### 函数定义 `memcpy` 的函数原型如下: ```c void *memcpy(void *dest, const void *src, size_t n); ``` - `dest`:目标内存地址,指向要复制数据到的位置。 - `src`:源内存地址,指向要复制的数据。 - `n`:要复制的字节数。 该函数不检查源数据是否包含终止空字符,因此它会精确地复制指定数量的字节[^2]。 #### 示例代码 以下是一个完整的示例,展示如何使用 `memcpy` 函数: ```c #include <iostream> #include <cstring> // 包含 memcpy 函数声明 using namespace std; int main() { char src[] = "Hello, World!"; char dest[50]; // 确保目标数组足够大以容纳源数据 printf("复制前: %s\n", dest); // 输出未初始化的目标数组内容(可能为垃圾值) // 使用 memcpy 将 src 中的 13 字节复制到 dest memcpy(dest, src, strlen(src) + 1); // 加 1 是为了复制字符串的终止符 '\0' printf("复制后: %s\n", dest); return 0; } ``` 在这个例子中,`strlen(src) + 1` 表示复制整个字符串及其终止符。如果只复制部分字节,则目标字符串可能不完整或缺少终止符。 #### 注意事项 1. **内存重叠问题**:如果源和目标内存区域有重叠,`memcpy` 的行为是未定义的。在这种情况下,应使用 `memmove` 函数[^2]。 2. **缓冲区溢出**:确保目标缓冲区足够大以容纳源数据。否则,可能会导致缓冲区溢出,进而引发程序崩溃或安全漏洞。 3. **二进制数据复制**:`memcpy` 不仅可以复制字符串,还可以复制任何类型的二进制数据。例如,复制结构体或数组。 #### 结果分析 在提供的示例代码中: ```c char src[] = "***"; char dest[] = "abcdefg"; printf("使用 memcpy 前: %s\n", dest); memcpy(dest, src, strlen(src)); printf("使用 memcpy 后: %s\n", dest); ``` 运行结果将是: ``` 使用 memcpy 前: abcdefg 使用 memcpy 后: ***defg ``` 这里,`memcpy` 将 `src` 中的 3 个星号覆盖了 `dest` 的前 3 个字符,其余部分保持不变[^1]。 ### 总结 `memcpy` 是一个高效且简单的函数,适用于各种内存复制场景。但在使用时需注意避免内存重叠和缓冲区溢出问题。
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值