当前位置: 首页 > news >正文

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,所以最后会得到12121218memmove(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个字节替换成了xmemset(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以外的数,不能用memsetfor(int i = 0; i < 5; i++){printf("%d ",arr1[i]);}
}

相关文章:

  • 打豆豆game
  • 带你玩转OpenHarmony AI:打造智能语音子系统
  • SpringBoot基础详解
  • 指针变量加1为什么地址加了4?
  • Python01:初入Python(Mac)
  • 【计算机视觉(3)】
  • Docker 安装最新版MongoDB 限制内存 配置权限
  • 电影《朝云暮雨》观后感
  • SW 草图明显显示
  • C++---运算符重载
  • VUE3好看的酒网站模板源码
  • [猫头虎分享21天微信小程序基础入门教程]第13天:小程序的表单与用户输入处理
  • 9.6 Go语言入门(数组、切片和指针)
  • 深度学习之基于YOLOV5安全帽检测系统
  • k8s基础命令
  • 【译】JS基础算法脚本:字符串结尾
  • 【跃迁之路】【641天】程序员高效学习方法论探索系列(实验阶段398-2018.11.14)...
  • CSS居中完全指南——构建CSS居中决策树
  • DOM的那些事
  • PAT A1050
  • PHP CLI应用的调试原理
  • 从0搭建SpringBoot的HelloWorld -- Java版本
  • 服务器从安装到部署全过程(二)
  • 数据库写操作弃用“SELECT ... FOR UPDATE”解决方案
  • #C++ 智能指针 std::unique_ptr 、std::shared_ptr 和 std::weak_ptr
  • (10)STL算法之搜索(二) 二分查找
  • (14)目标检测_SSD训练代码基于pytorch搭建代码
  • (附源码)计算机毕业设计高校学生选课系统
  • (一)使用Mybatis实现在student数据库中插入一个学生信息
  • (转)C#开发微信门户及应用(1)--开始使用微信接口
  • (转)Spring4.2.5+Hibernate4.3.11+Struts1.3.8集成方案一
  • (转)winform之ListView
  • .net core 3.0 linux,.NET Core 3.0 的新增功能
  • .net core webapi 部署iis_一键部署VS插件:让.NET开发者更幸福
  • .net core 客户端缓存、服务器端响应缓存、服务器内存缓存
  • .NET Core、DNX、DNU、DNVM、MVC6学习资料
  • .net framework 4.0中如何 输出 form 的name属性。
  • .Net Framework 4.x 程序到底运行在哪个 CLR 版本之上
  • .net refrector
  • .NET开发不可不知、不可不用的辅助类(一)
  • /usr/bin/env: node: No such file or directory
  • :O)修改linux硬件时间
  • @converter 只能用mysql吗_python-MySQLConverter对象没有mysql-connector属性’...
  • @RequestBody与@RequestParam
  • [ Linux Audio 篇 ] 音频开发入门基础知识
  • [20180129]bash显示path环境变量.txt
  • [AIGC] Kong:一个强大的 API 网关和服务平台
  • [Big Data - Kafka] kafka学习笔记:知识点整理
  • [Bugku]密码???[writeup]
  • [BZOJ1089][SCOI2003]严格n元树(递推+高精度)
  • [DEBUG] spring boot-如何处理链接中的空格等特殊字符
  • [Flutter]设置应用包名、名称、版本号、最低支持版本、Icon、启动页以及环境判断、平台判断和打包
  • [HJ56 完全数计算]
  • [iOS]GCD(一)
  • [iOS]-网络请求总结