内存函数的介绍及模拟实现

简介: 内存函数的介绍及模拟实现

内存函数的介绍及模拟实现


 今天的这篇博客主要是向大家介绍内存函数以及如何模拟实现内存函数。内存函数,顾名思义就是操作内存的函数,也是非常常用的一类函数,主要包括memcpy、memmove、memcmp和memset。首先,我们来学习memcpy。


1.memcpy


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


8c0bc9f119b04e91a21d8248da5281c5.png


 对于memcpy函数,我们需要注意一下几点:


  • 函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
  • 这个函数在遇到 '\0' 的时候并不会停下来。

代码示例:


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

b426d1ac6e3a4631a516fe34de0acf06.png


模拟实现memcpy函数 :


#include <stdio.h>
#include <string.h>
#include <assert.h>
void* my_memcpy(const void* dest, const void* source, size_t num)
{
  void* ret = dest;
  assert(dest && source);
  while (num--)
  {
    *(char*)dest = *(char*)source;
    dest = (char*)dest + 1;
      source = (char*)source + 1;
  }
  return ret;
}
int main()
{
  int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
  int arr2[10] = { 0 };
    //memcpy - 内存拷贝
    //模拟实现memcpy函数
  my_memcpy(arr2, arr1, 40);
  for (int i = 0; i < 10; i++)
  {
    printf("%d ", arr2[i]);
  }
  return 0;
}


注意事项: 因为dest和source都是无类型指针,不知道解引用访问几个字节,也不知道加一跳过几个字节,所以将它们都强制类型转化为char*,一个字节一个字节来交换。


 如果我们想调用自己定义的my_memcpy函数来将数组的数据拷贝到数组的另一个位置上,这样可不可以呢?现在我们来尝试一下。


代码示例:


#include <stdio.h>
#include <string.h>
#include <assert.h>
void* my_memcpy(const void* dest, const void* source, size_t num)
{
  void* ret = dest;
  assert(dest && source);
  while (num--)
  {
    *(char*)dest = *(char*)source;
    dest = (char*)dest + 1;
      source = (char*)source + 1;
  }
  return ret;
}
int main()
{
  int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
    //memcpy - 内存拷贝
    //模拟实现memcpy函数
  my_memcpy(arr1+2, arr1, 20);
  for (int i = 0; i < 10; i++)
  {
    printf("%d ", arr1[i]);
  }
  return 0;
}


输出结果:

82007fc22e4c4dbb92e9a23f32e1ee04.png


代码分析:

84a5f83fe618477d8da73b0ee54be313.png


我们可以看到,用我们自己定义的my_memcpy函数不能完成这个任务。那么我们用库函数memcpy能不能完成这个任务呢?我们现在来试一试。


代码示例 :


int main()
{
  int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
    //memcpy - 内存拷贝
  memcpy(arr1+2, arr1, 20);
  for (int i = 0; i < 10; i++)
  {
    printf("%d ", arr1[i]);
  }
  return 0;
}


输出结果:

b1bcae0e63c3426c8334bad96b55d1d2.png


 可以看到,用memcpy函数出色地完成了我们的任务。那为什么会这样呢?


代码分析:


 对于memcpy函数,只要实现了不重叠拷贝就可以了。但是在VS中的memcpy函数既可以实现不重叠拷贝,也可以实现重叠拷贝!!!相当于你只要求一个学生考60分,但是结果他给你考了个100分。不过,memcpy函数在其他编译器就有可能实现不了重叠拷贝。


想要实现重叠拷贝,就要借助另外一个内存函数了,就是memmove函数。


2.memmove


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


e049c3d84bb747a5ab005e47a0ba19f3.png

 对于memmove函数,我们需要注意一下几点:


  • 和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
  • 如果源空间和目标空间出现重叠,就得使用memmove函数处理。

代码示例:


#include <stdio.h>
#include <string.h>
int main()
{
  //memmove函数可以处理内存重叠的情况
  int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
  memmove(arr, arr+2, 20);
  for (int i = 0; i < 10; i++)
  {
    printf("%d ", arr[i]);
  }
  return 0;
}


c6913edd05c447bebc7a90baa2f32cd1.png


 我们可以看到,memmove函数将3 4 5 6 7移动到1 2 3 4 5的位置上了。其实学会使用memmove函数并不难,真的有难度的是如何去模拟实现memmove函数。


 在模拟实现memmove函数之前,我们先来分析一下。

4af4bcecb7794c1b924dc275aa719e9c.png


了解了模拟实现memmove函数的基本思路,现在我们一起来模拟实现memmove函数。


模拟实现memmove函数:


#include <stdio.h>
#include <string.h>
void* my_memmove(void* dest, const void* source, size_t num)
{
  //可以把原数据-从前往后拷贝,也可以从后向前拷贝
  //dest的地址高于source的地址时,先把数据拷给高地址,再把数据拷给低地址(从后往前拷贝)
  //dest的地址低于source的地址时,先把数据拷给低地址,再把数据拷给高地址(从前往后拷贝)
  assert(dest && source);
  void* ret = dest;
  if (dest < source)
  {
    //第一种情况:从前向后拷贝
    while (num--)
    {
      *(char*)dest = *(char*)source;
      dest = (char*)dest + 1;
      source = (char*)source + 1;
    }
  }
  else
  {
    //第二种情况:从后向前拷贝
    while (num--)//注意这时num的值已经减了一
    {
      *((char*)dest + num) = *((char*)source + num);
    }
  }
  return ret;
}  
int main()
{
  //memmove函数可以处理内存重叠的情况
  int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
  my_memmove(arr, arr+2, 20); 
  for (int i = 0; i < 10; i++)
  {
    printf("%d ", arr[i]);
  }
  return 0;
}


3.memcmp


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

a51796e0a6c242bcb899475c66387b5f.png

 对于memcmp函数,我们需要注意的是:memcmp函数比较数据大小是一个字节一个字节的数据来比较的,比较num个字节的数据。


代码示例:


#include <stdio.h>
#include <string.h>
int main()
{
  float arr1[] = { 1.0,2.0,3.0,4.0 };
  float arr2[] = { 1.0,3.0 };
  int ret = memcmp(arr1, arr2, 8);
  printf("%d\n", ret);
  return 0;
}

5e07d230063342f8a35ec938cc6eef04.png


模拟实现memcmp函数:


//memcmp - 内存比较
#include <stdio.h>
#include <assert.h>
#include <string.h>
int my_memcmp(const void* ptr1, const void* ptr2, size_t num)
{
  while (*(char*)ptr1 == *(char*)ptr2)
  {
    ptr1 = (char*)ptr1 + 1;
    ptr2 = (char*)ptr2 + 1;
    num--;
    if (num == 0)
    {
      return 0;
    }
  }
  return (*(char*)ptr1 - *(char*)ptr2);
  //注意:不相等时,不一定返回值为1或者-1
}
int main()
{
  float arr1[] = { 1.0,2.0,3.0,4.0 };
  float arr2[] = { 1.0,2.0 };
  int ret = my_memcmp(arr1, arr2, 8);
  printf("%d\n", ret);
  return 0;
}
#include <stdio.h>
#include <assert.h>
#include <string.h>
int my_memcmp(const void* arr1, const void* arr2, size_t num)
{
  assert(arr1 && arr2);
  while (num--)
  {
    if (*(char*)arr1 != *(char*)arr2)
    {
      return *(char*)arr1 - *(char*)arr2;
    }
    arr1 = (char*)arr1 + 1;
    arr2 = (char*)arr2 + 1;
  }
  return 0;
}
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 
  int arr2[] = { 1,2,3,0,0 };//01 00 00 00 02 00 00 00 03 00 00 00 00 00 00 00 
  //int ret = memcmp(arr1, arr2, 13);
  int ret = my_memcmp(arr1, arr2, 10);
  printf("%d\n", ret);
  return 0;
}


4.memset


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

27f933cd239c4620bad9ad9d1b2bd09f.png


 对于memset函数,我们需要注意的是:memset函数是将一个字节的数据改为value,并不是直接将一个整型或者一个浮点数直接该成value。


代码示例:


#include <stdio.h>
#include <string.h>
int main()
{
  int arr[10] = { 0 };
  memset(arr, 1, 20);//以字节为单位设置内存
  for (int i = 0; i < 10; i++) 
  {
    printf("%d ", arr[i]);
  }
}

6b8ea4e9249446d2a1f66571c9e121e1.png


代码分析:

0a77e52923034b97a02b5d9f0cd7e572.png


e10ab1ad20f041febf198abaf0d0d889.png


模拟实现memset函数:


#include <stdio.h>
#include <assert.h>
void* my_memset(void* ptr, int value, size_t num)
{
  assert(ptr);
  void* ret = ptr;
  while (num--)
  {
    *(char*)ptr = value;
    ptr = (char*)ptr + 1;
  }
  return ret;
}
#include <stdio.h>
#include <string.h>
int main()
{
  int arr[10] = { 0 };
  my_memset(arr, 1, 20);//以字节为单位设置内存
  for (int i = 0; i < 10; i++) 
  {
    printf("%d ", arr[i]);
  }
}


 以上就是这篇博客的全部内容,主要介绍了memcpy、memmove、memcmp和memset四个内存函数以及模拟实现这四个内存函数。大家如果觉得有收获的话,可以点个赞支持一下!

相关文章
|
1月前
|
C语言 C++
C语言 之 内存函数
C语言 之 内存函数
34 3
|
28天前
|
程序员 C++ 容器
在 C++中,realloc 函数返回 NULL 时,需要手动释放原来的内存吗?
在 C++ 中,当 realloc 函数返回 NULL 时,表示内存重新分配失败,但原内存块仍然有效,因此需要手动释放原来的内存,以避免内存泄漏。
|
1月前
|
存储 程序员 编译器
C语言——动态内存管理与内存操作函数
C语言——动态内存管理与内存操作函数
|
5月前
|
C语言
【C语言】:动态内存管理函数malloc,calloc,realloc和free的介绍的介绍
【C语言】:动态内存管理函数malloc,calloc,realloc和free的介绍的介绍
65 0
|
1月前
|
编译器 C语言 C++
详解C/C++动态内存函数(malloc、free、calloc、realloc)
详解C/C++动态内存函数(malloc、free、calloc、realloc)
158 1
|
1月前
|
程序员 C语言
C语言内存函数精讲
C语言内存函数精讲
|
23天前
|
存储 C语言
【c语言】字符串函数和内存函数
本文介绍了C语言中常用的字符串函数和内存函数,包括`strlen`、`strcpy`、`strcat`、`strcmp`、`strstr`、`strncpy`、`strncat`、`strncmp`、`strtok`、`memcpy`、`memmove`和`memset`等函数的使用方法及模拟实现。文章详细讲解了每个函数的功能、参数、返回值,并提供了具体的代码示例,帮助读者更好地理解和掌握这些函数的应用。
19 0
|
1月前
|
C语言 C++
c语言回顾-内存操作函数
c语言回顾-内存操作函数
40 0
|
1月前
|
存储 C语言 C++
来不及哀悼了,接下来上场的是C语言内存函数memcpy,memmove,memset,memcmp
本文详细介绍了C语言中的四个内存操作函数:memcpy用于无重叠复制,memmove处理重叠内存,memset用于填充特定值,memcmp用于内存区域比较。通过实例展示了它们的用法和注意事项。
64 0
|
1月前
一刻也没有为它哀悼~接下来登场的是动态内存分配的malloc与realloc以及free函数
一刻也没有为它哀悼~接下来登场的是动态内存分配的malloc与realloc以及free函数
65 0