【C语言】12.C语言内存函数

news2024/11/7 20:23:08

文章目录

  • 1.memcpy使用和模拟实现
  • 2.memmove使用和模拟实现
  • 3.memset函数的使用
  • 4.memcmp函数的使用


memcpy:内存拷贝

memmove:内存移动

memset:内存设置

memcmp:内存比较

1.memcpy使用和模拟实现

memcpy:内存拷贝

void * memcpy ( void * destination, const void * source, size_t num );
                    目标空间的地址          源空间的地址        被拷贝的字节个数
返回的是目标空间的起始地址
void*指针接收任意参数的地址

函数memcpysource的位置开始向后复制num个字节的数据到destination指向的内存位置。

这个函数在遇到 ‘\0’ 的时候并不会停下来。

如果sourcedestination有任何的重叠,复制的结果都是未定义的。

#include <stdio.h>
#include <assert.h>

void* my_memcpy(void* dest, const void* src, size_t num) {
	int i = 0;
	void* ret = dest;
	assert(src && dest);

	while (num--) {
		*(char*)dest = *(char*)src;
		dest = (char*)dest + 1;
		src = (char*)src + 1;
	}

	return ret;
}

int main() {
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[20] = { 0 };
	//将arr1中的34567拷贝到arr2中
	my_memcpy(arr2, arr1 + 2, 20);

	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr2[i]);
	}
	return 0;
}

打印:

3 4 5 6 7 0 0 0 0 0

注意:对于重叠的内存,交给memmove来处理。

重叠的意思就是:

my_memcpy(arr1 + 2, arr1, 20);

比如你想把arr数组里的某些数用arr数组的某些数替换,这样会出问题。

例如:

void* my_memcpy(void* dest, const void* src, size_t num) {
	int i = 0;
	void* ret = dest;
	assert(src && dest);

	while (num--) {
		*(char*)dest = *(char*)src;
		dest = (char*)dest + 1;
		src = (char*)src + 1;
	}

	return ret;
}

int main() {
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	//我们的想法是:将arr1中的12345拷贝到arr1中原来34567的地方,将原来的覆盖
	my_memcpy(arr1 + 2, arr1, 20);

	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr1[i]);
	}
	return 0;
}

打印:

1 2 1 2 1 2 1 8 9 10

打印这个玩意儿?怎么和猜的不一样呢?

1 2 3 4 5 6 7 8 9 10

程序里先把1替换了3

1 2 1 4 5 6 7 8 9 10

然后2替换了4

1 2 1 2 5 6 7 8 9 10

然后原来3位置的1替换了5

1 2 1 2 1 6 7 8 9 10

然后原来4位置的2替换了6

1 2 1 2 1 2 7 8 9 10

然后原来5位置的1替换了7

1 2 1 2 1 2 1 8 9 10

memcpy函数不负责重叠内存的拷贝,只负责不重叠的内存,非要使用,结果就是未定义的。

不过说是这么说,有些时候memcpy也能实现重叠内存的拷贝。我们可以认为memcpy实现的拷贝不一定都对。所以重叠就用memmove函数。

memmove函数来处理重叠内存的拷贝。


2.memmove使用和模拟实现

memmove:内存移动

void * memmove ( void * destination, const void * source, size_t num );

memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。

如果源空间和目标空间出现重叠,就得使用memmove函数处理。

#include <string.h>

int main() {
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	//将arr1中的12345拷贝到arr1中原来34567的地方,将原来的覆盖
	memmove(arr1 + 2, arr1, 20);

	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr1[i]);
	}
	return 0;
}

打印:

1 2 1 2 3 4 5 8 9 10

在这里插入图片描述

这个函数实际上就是实现src拷贝到dest。

如果是上面一种情况的话,我们可以先把3给1,然后把4给2,然后把5给3…这样就可以实现重叠内存的处理。(从前向后)

如果是中间一种情况的话,我们可以先把7给9,然后把6给8,然后把5给7…这样就可以实现重叠内存的处理。(从后向前)

如果是下面一种情况的话,我们可以按顺序把3给8,把4给9,把5给10…这样就可以实现重叠内存的处理。(从后向前)

在这里插入图片描述

两个紫色竖线表示的位置分别为src的起始位置和结束位置。

这两根紫色竖线把情况分成了三种。

第一种情况是(从前向后)

第二种情况是(从后向前)

模拟实现:

void* my_memmove(void* dest, const void* src, size_t num) {
	void* ret = dest;
	assert(src && 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 ret;
}

int main() {
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	//将arr1中的12345拷贝到arr1中原来34567的地方,将原来的覆盖
	my_memmove(arr1 + 2, arr1, 20);

	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr1[i]);
	}
	return 0;
}

打印:

1 2 1 2 3 4 5 8 9 10

3.memset函数的使用

memset:内存设置

void * memset ( void * ptr, int value, size_t num );

memset是用来设置内存的,将内存中的值以字节为单位设置成想要的内容。

#include <stdio.h>
#include <string.h>
int main ()
{
    char str[] = "hello world";
    memset (str,'x',6);
    printf(str);
    return 0;
}

打印:

xxxxxxworld

4.memcmp函数的使用

memcmp:内存比较

int memcmp ( const void * ptr1, const void * ptr2, size_t num );

比较从ptr1和ptr2指针指向的位置开始,向后的num个字节

返回值如下:

在这里插入图片描述


#include <stdio.h>
#include <string.h>
int main()
{
    int arr1[] = { 1,2,3,4,5 };
    //01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00
    int arr2[] = { 1,2,3,6,5 };
    //01 00 00 00 02 00 00 00 03 00 00 00 06 00 00 00 05 00 00 00
    int ret = memcmp(arr1, arr2, 12);
    printf("%d\n", ret);
    return 0;
}

打印:

0

因为前12个字节一样


#include <stdio.h>
#include <string.h>
int main()
{
    int arr1[] = { 1,2,3,4,5 };
    //01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00
    int arr2[] = { 1,2,3,6,5 };
    //01 00 00 00 02 00 00 00 03 00 00 00 06 00 00 00 05 00 00 00
    int ret = memcmp(arr1, arr2, 13);
    printf("%d\n", ret);
    return 0;
}

打印:

-1

因为第13个字节不一样

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

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

相关文章

【python】OpenCV—Background Estimation(15)

文章目录 中值滤波中值滤波得到图像背景移动侦测 学习来自 OpenCV基础&#xff08;14&#xff09;OpenCV在视频中的简单背景估计 中值滤波 中值滤波是一种非线性平滑技术&#xff0c;主要用于数字信号处理&#xff0c;特别是在图像处理中去除噪声。 一、定义与原理 定义&am…

如何使用Python在word文档中创建表格

如何使用Python在word文档中创建表格 介绍效果代码 介绍 本文将介绍如何使用Python库python-docx在Word文档中创建表格。 效果 插入表格前的word文档&#xff1a; 插入表格后的word文档&#xff1a; 代码 from docx import Document# 加载现有的Word文档 doc Document(…

利安科技上市首日股价大涨:2023营收净利润下滑,募资金额大幅缩水

《港湾商业观察》施子夫 6月7日&#xff0c;宁波利安科技股份有限公司&#xff08;以下简称&#xff0c;利安科技&#xff09;正式在深交所创业板挂牌上市&#xff0c;股票简称为利安科技&#xff0c;股票代码300784。 上市当天&#xff0c;利安科技股价大涨348.76%。 2022年…

高考志愿填报,如何识别兴趣和擅长?

一年一度的高考落下帷幕&#xff0c;是不是就意味着放松了&#xff1f;解放了&#xff1f; 高考志愿填报的重要性&#xff0c;依旧重要&#xff0c;考得好不如报的好。 考分高低固然是关键&#xff0c;而填报高考志愿&#xff0c;才是真正决定人生的一次选择&#xff0c;这一…

vue3 defineComponent + 渲染函数h + 全局注册​

defineComponent 是 Vue 3 中的一个函数&#xff0c;用于定义一个组件。它是 Vue 3 的组合式 API 的一部分&#xff0c;提供了一种更加灵活和组织化的方式来定义组件。在 Vue 2 中&#xff0c;我们通常使用一个对象来定义组件&#xff0c;而在 Vue 3 中&#xff0c;defineCompo…

Python深度学习基于Tensorflow(17)基于Transformer的图像处理实例VIT和Swin-T

文章目录 VIT 模型搭建Swin-T 模型搭建参考 这里使用 VIT 和 Swin-T 在数据集 cifar10 上进行训练 VIT 模型搭建 导入需要的外部库 import numpy as np import tensorflow as tf import matplotlib.pyplot as plt import matplotlib.gridspec as gridspec这里我们接着使用 ci…

idea开发工具清除Git凭证(含Git凭证管理策略)

前言 网上很多人出现这个问题&#xff0c;也有很多文章或博客来说明这个问题&#xff0c;但是几乎都没有说到点子上&#xff0c;全网几乎都说清除credential.helper配置或者清空windows凭证管理器&#xff0c;还有一些文章说清除IDEA缓存&#xff0c;其实都是不对的。 creden…

我在地球学Python基础第一篇:计算机组成原理基本知识和编程语言基础知识

业精于勤荒于嬉&#xff0c;行成于思毁于随。 今天开始系统记录学习Python 第一篇 计算机组成原理一、什么是计算机二、计算机是由什么组成的&#xff1f;2.1 硬件系统2.2 软件系统 三、计算机如何处理程序&#xff1f;四、编程语言 计算机组成原理 学习目标&#xff1a; 1、…

【docker实战】如何上传镜像到自己的私有仓库

上一篇文章讲了【docker实战】如何登陆到自己的私有仓库&#xff1f; – 经云的清净小站 (skycreator.top)。那么后面的工作就是如何上传镜像到自己的私有仓库了。 下面的操作是使用docker login命令成功之后的操作&#xff0c;没有login请先login。 我打算将本地的ubuntu:18…

攻防演练之-网络安全产品大巡礼二

书接上文&#xff0c;《网络安全攻防演练风云》专栏之攻防演练之-网络安全产品大巡礼一&#xff0c;这里。 “咱们中场休息一会&#xff0c;我去接杯水哈”&#xff0c;看着认真听讲的众人&#xff0c;王工很是满意&#xff0c;经常夹在甲乙两方受气的他&#xff0c;这次终于表…

在Spring Boot中使用Sa-Token实现路径拦截和特定接口放行

在Spring Boot中使用Sa-Token实现路径拦截和特定接口放行 很喜欢的一段话&#xff1a;别想太多&#xff0c;好好生活&#xff0c;也许日子过着过着就会有答案&#xff0c;努力走着走着就会有温柔的着落。 春在路上&#xff0c;花在枝上&#xff0c;所有的美好都在路上&#xff…

Coap协议在物联网中的实战

1. 前言 提到CoAP不能不提MQTT协议&#xff0c;MQTT协议可以保持长链接&#xff0c;具有一定的实时性&#xff0c;云端向客户端发送消息&#xff0c;设备端可以在最短的时间内接收并作出响应&#xff0c;所以MQTT更适合于实时控制场景&#xff0c;需要保持长连接&#xff0c;不…

WDF驱动开发-I/O请求的处理(三)

创建框架请求对象 框架请求对象表示 I/O 管理器已发送到驱动程序的 I/O 请求。 基于框架的驱动程序通过调用 框架请求对象方法来处理每个 I/O 请求。 每个 I/O 请求都包含一个 WDM I/O 请求数据包 (IRP 结构) &#xff0c;但基于框架的驱动程序通常不需要访问 IRP 结构。 大…

【AI大模型】Transformers大模型库(八):大模型微调之LoraConfig

目录 一、引言 二、LoraConfig配置参数 2.1 概述 2.2 LoraConfig参数说明 2.3 代码示例 三、总结 一、引言 这里的Transformers指的是huggingface开发的大模型库&#xff0c;为huggingface上数以万计的预训练大模型提供预测、训练等服务。 &#x1f917; Transformers …

3.2 窗口滚动条

本节讲述窗口滚动条的简单使用方法。如果窗口客户区的内容太多&#xff0c;为了方便浏览窗口客户区的所有内容&#xff0c;就需要在创建窗口时添加窗口垂直或水平滚动条样式。窗口过程处理WM_CREATE消息时初始化滚动条的位置和滚动范围。窗口过程处理WM_VSCROLL或WM_HSCROLL消息…

讲透计算机网络知识(实战篇)01——计算机网络和协议

一、计算机网络和协议 1、网络和互联网络 1.1 网络、互联网、Internet 用交换机、集线器连接在一起的计算机构成一个网络。 用路由器连接多个网络&#xff0c;形成互联网。 全球最大的互联网&#xff1a;Internet。 1.2 网络举例 家庭互联网 图中的无线拨号路由器既是路由…

281 基于matlab的路径规划GUI交互

基于matlab的路径规划GUI交互。包括蚁量系统、蚁周系统、蚁密系统、蚁群系统、免疫混合算法。11种路径规划数据&#xff0c;最多225个规划点。蚁群和免疫算法的参数可进行设置&#xff0c;使得效果最佳。动态显示可视化规划结果。程序已调通&#xff0c;可直接运行。

防止Selenium被检测 Google Chrome 125

背景 最近在使用selenium自动播放学习课程&#xff0c;相信大家也有一些类似的使用场景。 能自动化的事情&#xff0c;绝不自己干。 为防止被检测是机器人做题&#xff0c;刷视频&#xff0c;需要做一些小调整。 先来看作为服务方维护者&#xff0c;是如何检测是Selenium打…

8.transformers量化

Transformers 核心设计Auto Classes Transformers Auto Classes 设计:统一接口、自动检索 AutoClasses 旨在通过全局统一的接口 from_pretrained() ,实现基于名称(路径)自动检索预训练权重(模 型)、配置文件、词汇表等所有与模型相关的抽象。 灵活扩展的配置AutoConfig…

uniapp地图自定义文字和图标

这是我的结构&#xff1a; <map classmap id"map" :latitude"latitude" :longitude"longitude" markertap"handleMarkerClick" :show-location"true" :markers"covers" /> 记住别忘了在data中定义变量…