• C语言内存函数


    C语言内存函数

    个人主页:大白的编程日记
    个人专栏:大白的编程日记


    前言

    哈喽,各位小伙伴大家好。今天小编给大家带来的是C语言内存函数内容的分享。话不多说,咱们进入正题!向大厂冲锋!

    一.memcpy函数

    1.1memcpy函数的使用

    void * memcpy ( void * destination, const void * source, size_t num );
    
    • 1

    memcpy函数是用来拷贝内存的函数。
    函数有三个参数分别是 destination source num。
    分别代表 拷贝目的地指针 拷贝源头指针 拷贝长度。
    那具体是如何使用的呢?

    • 具体功能
      函数memcpy从source的位置开始向后复制num个字节的数据到destination指向的内存位置。注意num的单位是字节。

    • 拷贝长度
      这个函数在遇到 ‘\0’ 的时候并不会停下来。只会根据num的指定的长度拷贝内存,单位是字节。

    • 重叠问题
      如果source和destination有任何的重叠,复制的结果都是未定义的。内存重叠的情况不适合用memcpy拷贝。

    • 头文件
      memcpy需要包含头文件string.h,不止memcpy,所有内存函数都需要包含头文件string.h。

    • 对比strcpy
      memcpy因为是拷贝内存,所以不会关心拷贝的类型。任何存储在内存中类型的数据都能拷贝。而strcpy只能用来拷贝字符串。

    例如拷贝整型时:

    #define _CRT_SECURE_NO_WARNINGS 1
    #include 
    #include 
    int main()
    {
    	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
    	int arr2[10] = { 0 };
    	memcpy(arr2, arr1, 20);//20个字节==5个整型
    	int i = 0;
    	for (i = 0; i < 10; i++)
    	{
    		printf("%d ", arr2[i]);
    	}
    	return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16


    注意这里的20是20个字节,不是整形。
    4*5==20。所以拷贝的是5个整型。
    所以memcpy的功能其实包含了strcpy。


    1.2memcpy的模拟实现

    接下来我们来模拟实现memcpy函数。
    因为是拷贝内存,所以我们直接根据num的长度,将源头souce指向的内存字节的内容拷贝到destination指向的内存字节即可。
    每次拷贝后指针向后souce和destination指针向后移动,继续拷贝。

    • 图解:

    void* my_memcpy(void* dst, const void* src, size_t count)
    {
    	void* ret = dst;//保存目的地起始地址
    	assert(dst);
    	assert(src);//断言
    	while (count--) {
    		*(char*)dst = *(char*)src;//拷贝
    		dst = (char*)dst + 1;
    		src = (char*)src + 1;//移动
    	}
    	return(ret);//返回目的地
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    这里为了能拷贝任意类型的数据,我们用void接收和返回。
    然后断言一下,确保不会对空指针解引用。然后我们强转成char
    的指针在拷贝,确保能访问到每个字节,可以拷贝任意长度的内存。
    我们再拷贝前先保留了目的地的起始地址,防止丢失。

    	(char*)dst++;
    	(char*)src++;//移动
    
    • 1
    • 2

    那我们移动可不可以写成这样呢?
    不行,因为这样的强转是临时的。
    如果要写的话应该写成这样

        ((char*)dst)++;
    	((char*)src)++;//移动
    
    • 1
    • 2

    二.memmove

    2.1memmove的使用

    前面我们说memcpy不能拷贝内存重叠的情况。
    那内存重叠的情况怎么拷贝呢?这时候就需要memmove函数了。

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

    memmove函数的参数和返回值与memcpy一样。

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

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

    #define _CRT_SECURE_NO_WARNINGS 1
    #include 
    #include 
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    我们从arr1向后拷贝5个元素到arr1+2的位置。存在内存重叠。
    在这里插入图片描述

    2.2memmove的模拟实现

    这里我们是不是还是跟memcpy一样一个一个从源头拷贝到目的地就可以了呢?

    void* my_memcpy(void* dst, const void* src, size_t count)
    {
    	void* ret = dst;//保存目的地起始地址
    	assert(dst);
    	assert(src);//断言
    	while (count--) 
    	{
    		*(char*)dst = *(char*)src;//拷贝
    		dst = (char*)dst + 1;
    		src = (char*)src + 1;//移动
    	}
    	return(ret);//返回目的地
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    • 验证

      这里我们需要对src和dst的位置进行分类讨论。
      当有重叠情况时:

    • src在dst前面

      如果src在dst前面,我们就从后往前拷贝。

    • src在dst后面

      如果src在dst前面,我们就从前往后拷贝。

    void* my_memmove(void* dst, void* src, size_t num)
    {
    	void* ret = dst;
    	assert(dst && src);
    	if (src > dst)//比较的是地址
    	{
    		//前——>后
    		while(num--)
    		{
    			*(char*)dst = *(char*)src;
    			dst = (char*)dst + 1;
    			src = (char*)src + 1;
    		}
    	}
    	else
    	{
    		//从后往前
    		while (num--)//循环
    		{
    			*((char*)dst+num) = *((char*)src+num);//num是向后移动的字节数
    		}
    	}
    	return ret;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    我们先保存目的地的起始地址。然后if判断。
    如果src > dst。那就从前往后拷贝。跟memcpy一样。
    如果src < dst。那就从后往前拷贝。
    我们用while循环拷贝每个字节,src+num找到拷贝的内存字节。

    • 图解


    每次循环num–,就是拷贝内存字节前移。

    • 验证

    三.memse函数的使用

    3.1memset的使用

    memset是用来设置内存的,将内存中的值以字节为单位设置成想要的内容。
    注意是内存字节而不是元素!

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

    memset函数有三个参数 prt value num。
    分别代表 设置内存字节的起始地址 设置字节的值 设置字节的长度。

    #include 
    #include 
    int main ()
    {
     char str[] = "hello world";
     memset (str,'x',6);
     printf(str);
     return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    这里我们用memset修改字符串。

    那可不可以修改整型呢?

    int main()
    {
    	int arr[5] = {0};
    	memset(arr, 1, 20);
    	for (int i = 0; i < 5; i++)
    	{
    		printf("%d ", arr[i]);
    	}
    	return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    这里我们想让memset把数组的每个整型改成1。

    结果却不是1。这是为什么呢?

    • 未修改前:

    • 修改后:

      因为memset是以字节为单位修改,并不是以元素为单位修改。
      所以memset只会把每个字节改成1。这样输出的数就是0x01010101。转化为10进制就是16843009。
      所以我们在使用memset要特别注意他修改的是字节!


    3.2memset的模拟实现

    void* my_memset(void* ptr, int value, size_t num)
    {
    	void* ret = ptr;
    	for (int i = 0; i < num; i++)
    	{
    		*((char*)ptr + i) = value;//修改内存
    	}
    	return ptr;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    我们先保存起点地址。然后用for循环。
    因为是字节修改,所以我们先把指针强制类型转化一下。
    然后让指针+i,跳过i个字节指向需要修改的字节。
    最后赋值即可。



    四.memcmp函数

    4.1memcmp函数的使用

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

    memcmp有三个参数 ptr1 ptr2 num。

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

    • 返回值

      ptr1字节>ptr2字节,返回大于0的数。
      ptr1字节=ptr2字节,返回等于0的数。
      ptr1字节


    4.2memcmp的模拟实现

    int my_memcmp(void* ptr1, void* ptr2, size_t num)
    {
    	while (--num &&*((char*)ptr1) == *((char*)ptr2))
    	{
    		ptr1=(char*)ptr1+1;
    		ptr2=(char*)ptr2+1;//移动
    	}//如果相同则一直比较直到不相同
    	//或者移动到最后一个最后一个字节。
    	//出循环后让字节内容作差即可。
    	return *((char*)ptr1) - *((char*)ptr2);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    我们用while循环判断字节是否相等,
    如果相等让字节继续移动。
    因为我们只比较num个字节
    所以我们循环num-1次,如果前num-1个字节都相等,
    那我们就用第num个字节作差。
    如果不相等退出,那我们也让他们作差。
    这样就实现了memcmp的模拟实现了。

    验证:

    • 大于

    • 等于

    • 小于


    后言

    这就是内存函数的使用和模拟实现啦!小伙伴们可以对内存函数多加使用和熟练掌握。
    感谢小伙伴的垂阅,今天就分享到这,咱们下棋见!拜拜~

  • 相关阅读:
    C++ Reference: Standard C++ Library reference: C Library: cmath: hypot
    20231109-【尚硅谷】3小时Ajax入门到精通学习笔记
    入局AI手机 苹果公布Apple Intelligence
    Linux的Jdk安装教程
    Centos在NAT模式下的设置
    编译mbedtls (mingw方式)
    代理模式和静态代理
    第四章 数字逻辑电路设计方法【Verilog】
    MASTER aborted replication with an error: NOAUTH Authentication required.
    Python编程 集合
  • 原文地址:https://blog.csdn.net/2301_81670477/article/details/138199168