首页 > 系统相关 >内存操作函数

内存操作函数

时间:2024-03-14 22:01:51浏览次数:19  
标签:函数 int s1 char source num 内存 操作 拷贝

1 memcpy函数

memcpy是内存操作函数,所在的头文件是#include<string.h>。

1.1memcpy功能

memcpy和strcpy有一点相似,但是strcpy只能进行字符串的拷贝,而它可以对各种类型都能进行拷贝,但是按字节去进行拷贝的,就比如你有2个整形数组:a1和a2;你想将a2里面四个元素拷贝进a1中,一个整形是4个字节,那么就要拷贝16个字节。

下面是他的这个函数的传参内容:

主要是三个参数:你要拷贝进的地址destination,你要拷贝内容的地址source和你要拷贝的字节数num。

例如:

#include <stdio.h>
#include <string.h>
int main()
{
 int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
 int arr2[10] = { 0 };
 memcpy(arr2, arr1, 20);
 int i = 0;
 for (i = 0; i < 10; i++)
 {
 printf("%d ", arr2[i]);
 }
 return 0;
}

 1.2模拟实现memcpy

我们模拟实现这个函数首先从他的传参入手,你传入的是两个地址和一个整形

然后因为可以是任意类型,所以我们用两个void*去接收,然后就一个字节一个字节的去拷贝,但是void*这种类型的指针不能直接解引用。所以我们先要进行强制类型转换成char*然后在进行拷贝。因为char类型是占一个字节,我们也是一个字节一个字节的拷贝,所以强转成字符型比较符合我们的要求。

代码:

void my_memcpy(void* s1, const void* s2, size_t num)     //void*的指针不能直接解应用
{
	while (num--)
	{
		*(char*)s1 = *(char*)s2;
		(char*)s1 = (char*)s1 + 1;
		(char*)s2 = (char*)s2 + 1;
	}
}
int main()
{
	int num;//拷贝的字节数
	int s1[20] = {1,2,3,4,5,6,7,9,0};
	int s2[20] = { 2,3,4,5,6,7,89 };
	scanf("%d", &num);
	my_memcpy(s1, s2, num);
	for (int i = 0; i <= 19; i++)
	{
		printf("%d", s1[i]);
	}
	return 0;
}

 特别注意:memcpy对于destination和source有重叠的是候拷贝的结果是未定义,但是在我们vs2022memcpy是可以完成当这两个内存空间有重叠的情况。但是我们有另外一个操作数可以完成这个重叠时候的情况。

2 memmove函数

2.1memmove的功能

memmove函数可以去进行当destination和source有重合时就有可以用这个函数去进行拷贝。

也是按照字节去进行拷贝的,他的功能比memcpy多一些,

他的传参和memcpy一样。

用法举例:

#include <stdio.h>
#include <string.h>
int main()
{
 int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
 memmove(arr1+2, arr1, 20);
 int i = 0;
 for (i = 0; i < 10; i++)
 {
 printf("%d ", arr1[i]);
 }
return 0;
}

 2.2memmove的模拟实现

memmove因为可以进行重叠部分时拷贝的功能,所以他的模拟实现比memcpy稍微复杂一点。

这个重叠时候的情况还分为两种:

一种是destination在source的前面。

一种是source在destination的后面。

首先我们来讲第一种情况:

第一种情况是我们就要从前到后拷贝,这样你会将你没有进行拷贝的内容覆盖了,

第二种情况 就是需要我们要去从后往前拷贝才能不被覆盖掉。

void* my_memmove(void* destination, const void* source, int num)
{
	if (destination < source)//前到后
	{
		while (num--)
		{
			*(char*)destination = *(char*)source;
			destination = (char*)destination + 1;
			source = (char*)source + 1;
		}
	}
	else {//从后到前
		while (num--)
		{
			*((char*)destination + num)=*((char*)source+num);
		}
	}
}
int main()
{
	int s1[10] = { 1,2,3,4,5,6,7,8,9 };
	int num;
	scanf("%d", &num);
	my_memmove(s1 + 3, s1 + 2,num);
	for (int i = 0; i < 10; i++)
	{
		printf("%d", s1[i]);
	}
	return 0;
}

要注意的是当destination < source这一种情况是:

 destination = (char*)destination + 1;
   source = (char*)source + 1;

这两个语句不能写成destination++和source++;

因为我们这里的两个指针是void*

你要他自己去进行++的话,他不知道走多远,他没有具体类型,所以这里你要进行强转,再去进行++。

3 memset函数的使用

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

ptr是你想改换内容的地址,value是想要你要改成什么内容,num是改多少个字节。

例如:

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

 

4memcmp函数的使用

这个函数是进行字节内容进行比较的

从ptr1和ptr2指针指向的位置开始,向后的num个字节进行比较 如果相同返回0; 不相同返回:ptr1>ptr2的话返回大于零的数,小于就是返回小于零的数。 例如:
#include <stdio.h>
#include <string.h>
int main()
{
 char s1[] = "DWgaOtP12df0";
 char s2[] = "DWGAOTP12DF0";
 int n;
 n = memcmp(s1, s2, sizeof(s1));
 if (n > 0) 
 printf("'%s' is greater than '%s'.\n", s1, s2);
 else if (n < 0) 
 printf("'%s' is less than '%s'.\n", s1, s2);
 else
 printf("'%s' is the same as '%s'.\n", s1, s2);
 return 0;
}

 

 

标签:函数,int,s1,char,source,num,内存,操作,拷贝
From: https://blog.csdn.net/2301_80028974/article/details/136721305

相关文章

  • 操作符简单介绍;
    除法操作符;1.‘/’除法运算符两边都是整数时,操作结果也是整数;当两边至少有一个小数时,算出来的是小数;2.代码:intmain(){ doublez=7/2;//整数除法算出的是3,打印的时候跟类型无关; doublex=7.0/2;//小数除法必须至少有一个是小数; printf("%lf\n",z);//除法中被除......
  • C++函数模板的实参推断
    C++模板在使用类模板创建对象时,程序员需要显式的指明实参(也就是具体的类型)。例如对于下面的Point类:template<typename T1, typename T2> class Point;我们可以在栈上创建对象,也可以在堆上创建对象:Point<int, int> p1(10, 20);  //在栈上创建对象Point<char*, c......
  • C++函数模板的重载
    C++模板当需要对不同的类型使用同一种算法(同一个函数体)时,为了避免定义多个功能重复的函数,可以使用模板。然而,并非所有的类型都使用同一种算法,有些特定的类型需要单独处理,为了满足这种需求,C++允许对函数模板进行重载,程序员可以像重载常规函数那样重载模板定义。我们定义了Swap(......
  • Go语言中接口和函数的用法
    函数:在Go语言中,函数是一等公民,可以像其他变量一样被传递、赋值和使用。函数可以单独定义,也可以作为匿名函数或闭包使用。可以定义带有参数和返回值的函数,函数可以作为参数传递给其他函数,也可以作为返回值返回给其他函数。函数也可以被用来实现接口中的方法。接口:接口是......
  • 数据在内存中的存储
    一、整数在内存中的存储1.1原码、反码、补码    整数的二进制表示方法有三种,即:原码、反码、补码。    有符号的整数,三种表示方法均有数值位和符号位两部分,其中0表示正,1表示负,最高位的一位被称作是符号位,其余的均为数值位。    正数的原码、反码、......
  • nmap 进行网络扫描详细操作
    1.安装nmap首先,您需要在您的系统上安装nmap。这通常可以通过系统的包管理器来完成。以下是一些常见发行版的安装命令:对于Debian/Ubuntu系统:sudoaptupdate sudoaptinstallnmap对于CentOS/RedHat系统:sudoyumupdate sudoyuminstallnmap对于macOS......
  • Python自学☞序列和索引的相关操作
    一、基本概念1、概念序列是一个用于存储多个值的连续空间,每个值都对应一个整数的编号,称为索引2、切片的语法结构注:切片可以访问序列一定范围内的元素序列[start:end:step]    start-->切片的开始索引(包含)    end-->切片的结束索引(不包含)  step-->步长(默......
  • 01了解操作系统
    硬件和软件们所熟知的计算机是由:硬件和软件所组成硬件计算机系统中由电子,机械和光电元件等组成的各种物理装置的总称软件软件是用户和计算机硬件之间的接口和桥梁,用户通过软件与计算机进行交流。而操作系统,就是软件的一类。操作系统操作系统是计算机软件的一种,它主要负......
  • 整型变量的原子操作
    什么是原子操作原子操作(AtomicOperation)是指不可中断的操作,即在多线程环境下,当一个线程在执行原子操作时,不会被其他线程的调度和中断所影响。这种操作在多线程编程中尤为重要,因为它能保证操作的原子性,从而避免数据竞争和不一致。原子操作的特性原子性:操作不可分割,即不可中......
  • 操作MySQL之mysql库
    目录一、快速使用1.下载2.快速链接3.最佳使用方案4.设置连接池二、查询数据1.单行查询db.QueryRow()2.多行查询db.Query()三、插入数据四、删除数据五、更新数据六、MySQL预处理1.什么是预处理?2.为什么要预处理?3.Go实现MySQL预处理4.SQL注入问题七、Go实现MySQL事务1.......