C语言常用的内存操作函数

        在C语言中经常会操作内存中的数据,下面来介绍一下常用的一些内存操作函数。

memcpy

        memcpy用于从source的位置开始向后复制num个字节到destination的内存位置,其函数原型如下:

//destination是目标地址,source是源地址,num是要复制的字节数,返回的是目标地址。因为不知道内存中存储的是什么数据类型,所以都用void*
void * memcpy ( void * destination, const void * source, size_t num );

        下面举一个应用的例子:

#include <stdio.h>
#include <string.h>
struct
{
    char name[40];
    int age;
} person, person_copy;
int main()
{
    char myname[] = "Pierre de Fermat";
    /* using memcpy to copy string: */
    memcpy(person.name, myname, sizeof(myname));
    person.age = 46;
    /* using memcpy to copy structure: */
    memcpy(&person_copy, &person, sizeof(person));
    printf("person_copy: %s, %d \n", person_copy.name, person_copy.age);
    return 0;
}

        需要注意的是,C标准规定使用memcpy拷贝的目标地址和源地址空间不能出现重叠,否则会出错(vs编译器对memcpy进行了优化,使其空间可以重叠):

int main()
{
    int arr[] = {1, 2, 3, 4, 5, 6, 7, 8};
//这里是想把12345拷贝到34567的位置,预期结果是12123458,按照C语言标准,如果使用memcpy当把12拷贝到34位置后,继续应该把34拷贝到56的位置,而此时34已经变成了12,所以还会把12拷贝到56,然后把5拷贝到7,此时5已经变成了1,所以最后会得到12121218
    memmove(arr + 2, arr, 5 * sizeof(int));
    for (int i = 0; i < 8; i++)
    {
        printf("%d ", arr[i]);//这里可以正常打印出12123458,是因为vs编译器进行了优化
    }
    return 0;
}

        下面来模拟实现一下memcpy函数:

/*
 * @brief    内存拷贝函数,将src地址开始的num个字节的数据拷贝到dest
 * @param    dest:目标地址
 * @param    src:源地址
 * @param    num:拷贝的字节数
 * @return   void*: 返回dest
 */
void *my_memcpy(void *dest, const void *src, size_t num)
{
    assert(dest && src);//防止传入空指针
    void *temp = dest;//用于返回
    while (num--)//循环num次,每次拷贝一个字节
    {
        *(char *)dest = *(char *)src;//先把两个地址强转成char*,每次操作一个字节
        dest = (char *)dest + 1;//操作完一次后地址++
        src = (char *)src + 1;
    }
    return temp;//返回目标地址
}

memmove

        memmove就是在memcpy的基础上增加了处理重叠内存的功能,其函数原型如下:

//destination是目标地址,source是源地址,num是要复制的字节数,返回的是目标地址。因为不知道内存中存储的是什么数据类型,所以都用void*
void * memmove ( void * destination, const void * source, size_t num );

        所以当destination小于source时,应该从前向后拷贝, destination大于source时,应该从后向前拷贝,下面来模拟实现一下memmove:

/*
 * @brief    内存移动,源和目标地址重叠时的memcpy
 * @param    dest:目标地址
 * @param    src:源地址
 * @param    num:要拷贝的字节数
 * @return   void*:返回目标地址
 */
void *my_memmove(void *dest, void *src, size_t num)
{
    assert(dest && src);
    void *temp = dest;
    if (dest < src) // 前->后
    {
        while (num--)
        {
            *(char *)dest = *(char *)src;
            dest = (char *)dest + 1;
            src = (char *)src + 1;
        }
    }
    else
    {
        while (num--) // 后->前
        {
            *((char *)dest + num) = *((char *)src + num);
        }
    }
    return temp;
}

memcmp

        memcmp用于比较两个内存中的内容是否相等,类似于strcmp,其函数原型如下:

//ptr1是第一块内存的起始地址,ptr2是第二块内存起始地址,num是要比较的字节数,如果第一块内存内容大于第二块,返回正数,反之返回负数,相等返回0
int memcmp ( const void * ptr1, const void * ptr2, size_t num );

memset

        memset用于设置指定内存中的数据,其函数原型如下:

//ptr是要设置的内存起始地址,value是要设置的值,num是要设置的字节数,返回ptr
void* memset(void* ptr, int value, size_t num);

        下面举一些应用例子:

int main()
{
    char arr[] = "hello world";
    int arr1[5] = {1,2,3,4,5};
    memset(arr,'x',5*sizeof(char));
    printf("%s\n",arr);//会打印xxxxx world,把前5个字节替换成了x
    memset(arr1,0,5*sizeof(int));
    for(int i = 0; i < 5; i++)
    {
        printf("%d ",arr1[i]);//会打印00000,将5个int型,也就是20个字节换成了0
    }
    memset(arr1,1,5*sizeof(int));
//会打印16843009 16843009 16843009 16843009 16843009,是将每个字节都换成了1,一个int有四个字节,所以如果想将一个int数组的每个元素设置成0以外的数,不能用memset
    for(int i = 0; i < 5; i++)
    {
        printf("%d ",arr1[i]);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值