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

news2024/12/26 22:40:24

        在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]);
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1688482.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

想要学会做抖店,每天重复这些步骤就可以了!

大家好&#xff0c;我是电商糖果 有很多朋友店铺开好之后&#xff0c;不知道每天要干嘛。 只知道把产品上架&#xff0c;然后等着出单。 说实话这种情况的朋友不是一个&#xff0c;而是很多。 糖果做小店也有很多年了&#xff0c;也开了多家店铺&#xff0c;下面就来给大家…

论Promise在前端江湖的地位及作用

系列文章&#xff1a; 先撸清楚&#xff1a;并发/并行、单线程/多线程、同步/异步 论Promise在前端江湖的地位及作用 前言 上篇文章阐述了并发/并行、单线程/多线程、同步/异步等概念&#xff0c;这篇将会分析Promise的江湖地位。 通过本篇文章&#xff0c;你将了解到&#x…

算法刷题笔记 数的范围(C++实现)(二分法重要例题)

文章目录 题目描述题目思路题目代码&#xff08;C&#xff09;题目感想 题目描述 给定一个按照升序排列的长度为n的整数数组&#xff0c;以及q个查询。对于每个查询&#xff0c;返回一个元素k的起始位置和终止位置&#xff08;位置从0开始计数&#xff09;。如果数组中不存在该…

Flutter 中如何优雅地使用弹框

日常开发中&#xff0c;Flutter 弹框&#xff08;Dialog&#xff09;是我们使用频率非常高的控件。无论是提示用户信息、确认用户操作&#xff0c;还是表单填写&#xff0c;弹框都能派上用场。然而&#xff0c;看似简单的弹框&#xff0c;实际使用起来却有不少坑和使用的技巧。…

轻松找回误删短信 | 超强安卓短信恢复神器

概括 我们都曾经历过不小心删除了重要消息&#xff0c;后来又后悔并认为可能无法恢复它们的情况。从技术上讲&#xff0c;该消息不会被删除&#xff1b;它会在您的 Android 手机上存储一段时间。 可以执行 Android 短信恢复&#xff0c;因为它需要一段时间才能从您的 Android…

JavaScript面试 题

1.延时加载JS有哪些方式 延时加载 :async defer 例如:<script defer type"type/javascript" srcscript.js></ script> defer:等html全部解析完成,才会执行js代码,顺次执行的 async: js和html解析是同步的,不是顺次执行js脚本(谁先加载完先执行谁)2.JS数…

黑龙江等保测评深入理解

“没有网络安全&#xff0c;就没有国家安全”&#xff0c;等级保护测评是指按照网络安全系统制定的一系列的防护过程&#xff0c;对已经有的和即将上线的商业服务的基础设施&#xff08;系统&#xff0c;数据库&#xff0c;中间件等&#xff09;所做的一系列的检查&#xff0c;…

代码随想录-Day18

513. 找树左下角的值 给定一个二叉树的 根节点 root&#xff0c;请找出该二叉树的 最底层 最左边 节点的值。 假设二叉树中至少有一个节点。 方法一&#xff1a;深度优先搜索 class Solution {int curVal 0;int curHeight 0;public int findBottomLeftValue(TreeNode roo…

Python筑基之旅-MySQL数据库(三)

目录 一、数据库操作 1、创建 1-1、用mysql-connector-python库 1-2、用PyMySQL库 1-3、用PeeWee库 1-4、用SQLAlchemy库 2、删除 2-1、用mysql-connector-python库 2-2、用PyMySQL库 2-3、用PeeWee库 2-4、用SQLAlchemy库 二、数据表操作 1、创建 1-1、用mysql-…

分布式理论--BASE

目录 是什么BASE 与 CAP&#xff0c;ACID 的区别BASE 和 Paxos 类共识算法的区别相关问题 是什么 BASE 理论是对 CAP 理论的进一步扩展主要强调在分布式系统中&#xff0c;为了获得更高的可用性和性能&#xff0c;可以放宽对一致性的要求&#xff0c;是对 CAP 中 AP 方案的一个…

卷爆短剧出海:五大关键,由AIGC重构

短剧高温下&#xff0c;谈谈AIGC的助攻路线。 短剧&#xff0c;一个席卷全球的高温赛道。 以往只是踏着霸总题材&#xff0c;如今&#xff0c;内容循着精品化、IP化的自然发展风向&#xff0c;给内容、制作、平台等产业全链都带来新机&#xff0c;也让短剧消费走向文化深处&am…

D60SB120-ASEMI整流桥D60SB120参数、封装、尺寸

编辑&#xff1a;ll D60SB120-ASEMI整流桥D60SB120参数、封装、尺寸 型号&#xff1a;D60SB120 品牌&#xff1a;ASEMI 封装&#xff1a;D-SB 批号&#xff1a;2024 最大重复峰值反向电压&#xff1a;1200V 最大正向平均整流电流(Vdss)&#xff1a;60A 功率(Pd)&#x…

Kubernetes 应用滚动更新

Kubernetes 应用版本号 在 Kubernetes 里&#xff0c;版本更新使用的不是 API 对象&#xff0c;而是两个命令&#xff1a;kubectl apply 和 kubectl rollout&#xff0c;当然它们也要搭配部署应用所需要的 Deployment、DaemonSet 等 YAML 文件。 在 Kubernetes 里应用都是以 …

uniapp开发vue3监听右滑返回操作,返回到指定页面

想要在uniapp框架中监听左滑或者右滑手势&#xff0c;需要使用touchstart和touchend两个api&#xff0c;因为没有原生的左右滑监听api&#xff0c;所以我们只能依靠这两个api来获取滑动开始时候的x坐标和滑动结束后的x坐标做比对&#xff0c;右滑的话&#xff0c;结束时候的x坐…

RabbitMQ(一)概述第一个应用程序

文章目录 概述AMQP和JMS官网安装开始第一个程序 概述 消息队列是实现应用程序和应用程序之间通信的中间件产品 AMQP和JMS 工作体系 官网 https://www.rabbitmq.com/ RabbitMQ是一款基于AMQP、由Erlang语言开发的消息队列产品 安装 # 拉取镜像 docker pull rabbitmq:3.13-m…

微信小程序画布显示图片绘制矩形选区

wxml <view class"page-body"><!-- 画布 --><view class"page-body-wrapper"><canvas canvas-id"myCanvas" type"2d" id"myCanvas" classmyCanvas bindtouchstart"touchStart" bindtouchmo…

UEFI EDK2源码学习(一)——环境安装

部署环境 vmvare15.0 ubuntu20.04 docker edk2 源码 具体步骤 docker安装 # 更新apt软件包索引 sudo apt-get update# 添加docker依赖 sudo apt-get install -y \apt-transport-https \ca-certificates \curl \gnupg-agent \software-properties-common# 添加docker 官方…

白嫖免费图床!CloudFlare R2太香了!

1 为啥要折腾搭建一个专属图床&#xff1f; 技术大佬写博客都用 md 格式&#xff0c;要在多平台发布&#xff0c;图片就得有外链后续如博客迁移&#xff0c;国内博客网站如掘金&#xff0c;简书&#xff0c;语雀等都做了防盗链&#xff0c;图片无法迁移 2 为啥选择CloudFlare…

力扣刷题---返回word中所有不重复的单词

当需要从一个数据集合中去除重复元素时&#xff0c;set是一个很好的选择。由于其不允许存储重复的元素&#xff0c;因此可以很容易地实现去重功能。这在处理原始数据或进行数据分析时特别有用。 题目&#xff1a; 给定一个字符串数组 words&#xff0c;请返回一个由 words 中所…

SpringCloud微服务03-微服务保护-分布式事务-MQ基础-MQ高级

一、微服务保护 1.雪崩问题 如何做好后备方案就是后续&#xff1a; 2.雪崩解决方案 某一个服务的线程是固定的&#xff0c;出现故障线程占满后&#xff0c;就不会让取调用这个服务&#xff0c;对其他服务就没有影响。 3.Sentinel ①初识Sentinel 配置过程&#xff1a;day05-服…