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

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

memcpy

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

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

下面举一个应用的例子:

cpp 复制代码
#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进行了优化,使其空间可以重叠):

cpp 复制代码
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函数:

cpp 复制代码
/*
 * @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的基础上增加了处理重叠内存的功能,其函数原型如下:

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

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

cpp 复制代码
/*
 * @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,其函数原型如下:

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

memset

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

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

下面举一些应用例子:

cpp 复制代码
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]);
    }
}
相关推荐
楼台的春风几秒前
【MCU驱动开发概述】
c语言·驱动开发·单片机·嵌入式硬件·mcu·自动驾驶·嵌入式
黑子哥呢?7 分钟前
安装Bash completion解决tab不能补全问题
开发语言·bash
青龙小码农12 分钟前
yum报错:bash: /usr/bin/yum: /usr/bin/python: 坏的解释器:没有那个文件或目录
开发语言·python·bash·liunx
大数据追光猿18 分钟前
Python应用算法之贪心算法理解和实践
大数据·开发语言·人工智能·python·深度学习·算法·贪心算法
彳卸风1 小时前
Unable to parse timestamp value: “20250220135445“, expected format is
开发语言
dorabighead1 小时前
JavaScript 高级程序设计 读书笔记(第三章)
开发语言·javascript·ecmascript
风与沙的较量丶2 小时前
Java中的局部变量和成员变量在内存中的位置
java·开发语言
水煮庄周鱼鱼2 小时前
C# 入门简介
开发语言·c#
编程星空3 小时前
css主题色修改后会多出一个css吗?css怎么定义变量?
开发语言·后端·rust
软件黑马王子3 小时前
Unity游戏制作中的C#基础(6)方法和类的知识点深度剖析
开发语言·游戏·unity·c#