内存函数的使用和模拟实现

简介: 那么今天我要分享的是内存函数,为什么我会给大家分享这个呢?或者说,内存函数的作用是什么呢?有了字符函数就行了,为什么还会有内存函数呢?那么我们就先来看看字符函数和字符串函数的局限性。字符函数和字符串函数,看见这个名字我们应该就可以知道这个函数的操作对象是什么了,没错,字符函数和字符串函数是操作字符和字符串的,但是平常生活中我们遇到的可不止有字符串,所以这时候就出现了内存函数,它的好处是:可以操作任意类型的数据,这样就极大的方便了我们了我们的生活。接下来我们就来看看这些内存函数是如何使用以及自己来模拟实现它。

memcmp

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

这个函数的意思是将ptr1中num个字节与ptr2中num个字节进行比较,ptr1大于ptr2则返回大于0的数,相等返回0,小于则返回一个小于0的数。我们先来使用库函数来看看memcmp是怎样工作的吧。

#include<stdio.h>
#include<string.h>
int main()
{
  int arr1[] = { 1,2,3,4,5,6 };
  int arr2[] = { 1,2,3,4,6,5 };
  int ret = memcmp(arr1, arr2, 16);
  printf("%d\n",ret);
  return 0;
}

43.png

#include<stdio.h>
#include<string.h>
int main()
{
  int arr1[] = { 1,2,3,4,5,6 };
  int arr2[] = { 1,2,3,4,6,5 };
  int ret = memcmp(arr1, arr2, 20);
  printf("%d\n",ret);
  return 0;
}

44.png


知道库函数memcmp是怎么工作的之后,我们就来自己模拟实现memcmp


模拟实现memcmp

#include<stdio.h>
//这里参数的类型为void,能接受任何类型的数据
int my_memcmp(const void* arr1, const void* arr2, size_t num)
{
    //因为不能对void类型的数据直接解引用,所以这里得强制类型转化为
    //char*类型,然后一个字节一个字节的操作。
  char* str1 = (char*)arr1; 
  char* str2 = (char*)arr2;
  while (num--)
  {
    if (*str1 != *str2)
    {
      return *str1 - *str2;
    }
    str1++;
    str2++;
  }
  return 0;
}
int main()
{
  int arr1[] = { 1,2,3,4,5,6 };
  int arr2[] = { 1,2,3,4,6,5 };
  int ret = my_memcmp(arr1, arr2, 20);
  printf("%d\n", ret);
  return 0;
}

45.png

memcpy

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

此函数的目的是将从source开始的num个字节的数据拷贝到destination中。先来使用库函数来实现这个功能。

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

46.png


然后就是我们自己来模拟实现memcpy


模拟实现memcpy

#include<stdio.h>
void* my_memcpy(void* destination, void* source, size_t num)
{
  char* str1 = (char*)destination;
  char* str2 = (char*)source;
  while (num--)
  {
    *str1 = *str2;
    str1++;
    str2++;
  }
  return destination;
}
int main()
{
  int arr1[] = { 1,2,3,4,5,6,7,8 };
  int arr2[10] = { 0 };
  my_memcpy(arr2, arr1, 6 * sizeof(int));
  for (int i = 0; i < 6; i++)
  {
    printf("%d ", arr2[i]);
  }
  return 0;
}

image.png


我们这里看到的是两块没有重叠的部分的拷贝,那么当我们的destination和source有重叠的时候这个memcpy能不能实现呢?我们来看看


#include<stdio.h>
void* my_memcpy(void* destination, void* source, size_t num)
{
  char* str1 = (char*)destination;
  char* str2 = (char*)source;
  while (num--)
  {
    *str1 = *str2;
    str1++;
    str2++;
  }
  return destination;
}
int main()
{
  int arr1[] = { 1,2,3,4,5,6,7,8 };
  my_memcpy(arr1+2, arr1, 4 * sizeof(int));
  for (int i = 0; i < 8; i++)
  {
    printf("%d ", arr1[i]);
  }
  return 0;
}

我们想要得到1,2,1,2,3,4,7,8的结果,可是呢?我们看看运行结果


48.png


这里并没有得到我们期待的结果,所以memcpy并不能处理有重叠的情况,那么接下来我要介绍的就可以处理有重叠情况的拷贝了。

 

memmove

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

这个函数的意思是,从source开始的num个字节移动到从destination开始的num个字节。

还是先来看看库函数是怎样使用的:

#include<stdio.h>
#include<string.h>
int main()
{
  int arr[6] = { 1,2,3,4,5,6 };
  memmove(arr, arr + 2, 4 * sizeof(int));
  for (int i = 0; i < 6; i++)
  {
    printf("%d ", arr[i]);
  }
  return 0;
}


image.png


当我们来自己实现的时候,我们要想想怎么做?是不是每一次都是从左往右来实现呢?我们来看一个例子:先给一个1-6的数组,然后我们的目的就是想要把1,2,3,4移动到3,4,5,6的位置,最后得到1,2,1,2,3,4,我们就按照从左往右的顺序来移动,看看结果会是怎么样的。


50.png


我们先移动1,2


51.png


此时原来的3,4的位置已经被改为了1,2,然后我们来继续移动


52.png


结果就是这样的,并不能得到我们想要的结果,那么这题应该怎么做呢?我们换个思路,从右往左移动,


53.png


那么我们就需要讨论,当需要移动的值跟destination以及后面的num个字节有重叠部分时,当destination>source时,就从右往左移动,相反就从左往右移动 ,当他们没有重叠部分就两种情况都可以,所以为了方便我们就将没有重叠的情况也从右往左移动。


模拟实现memmove

#include<stdio.h>
#include<assert.h>
void my_memmove(void* destination, void* source, size_t num)
{
  assert(destination && source);
  char* str1 = (char*)destination;
  char* str2 = (char*)source;
  if (str1 > str2 || (str1<str2 && str1+num<str2))
  {
    int tmp1 = num;
    while (tmp1--)
    {
      *(str1 + tmp1) = *(str2 + tmp1);
    }
  }
  else
  {
    int tmp2 = num;
    for (int i = 0; i < tmp2; i++)
    {
      *(str1 + i) = *(str2 + i);
    }
  }
}
int main()
{
  int arr[6] = { 1,2,3,4,5,6 };
  my_memmove(arr+2, arr, 4 * sizeof(int));
  for (int i = 0; i < 6; i++)
  {
    printf("%d ", arr[i]);
  }
  return 0;
}

image.png


再来看看另外一种情况是否也能得到结果。


#include<stdio.h>
#include<assert.h>
void my_memmove(void* destination, void* source, size_t num)
{
  assert(destination && source);
  char* str1 = (char*)destination;
  char* str2 = (char*)source;
  if (str1 > str2 || (str1<str2 && str1+num<str2))
  {
    int tmp1 = num;
    while (tmp1--)
    {
      *(str1 + tmp1) = *(str2 + tmp1);
    }
  }
  else
  {
    int tmp2 = num;
    for (int i = 0; i < tmp2; i++)
    {
      *(str1 + i) = *(str2 + i);
    }
  }
}
int main()
{
  int arr[6] = { 1,2,3,4,5,6 };
  my_memmove(arr, arr+2, 4 * sizeof(int));
  for (int i = 0; i < 6; i++)
  {
    printf("%d ", arr[i]);
  }
  return 0;
}

55.png

小结:


那么这些就是我学到的关于内存函数的内容了,感谢大家的观看,如遇错误的地方,欢迎大家指点,我们一起进步。

相关文章
|
1月前
|
C语言 C++
C语言 之 内存函数
C语言 之 内存函数
34 3
|
1月前
|
程序员 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)
176 1
|
1月前
|
程序员 C语言
C语言内存函数精讲
C语言内存函数精讲
|
27天前
|
存储 C语言
【c语言】字符串函数和内存函数
本文介绍了C语言中常用的字符串函数和内存函数,包括`strlen`、`strcpy`、`strcat`、`strcmp`、`strstr`、`strncpy`、`strncat`、`strncmp`、`strtok`、`memcpy`、`memmove`和`memset`等函数的使用方法及模拟实现。文章详细讲解了每个函数的功能、参数、返回值,并提供了具体的代码示例,帮助读者更好地理解和掌握这些函数的应用。
23 0
|
1月前
|
C语言 C++
c语言回顾-内存操作函数
c语言回顾-内存操作函数
40 0
|
1月前
|
存储 C语言 C++
来不及哀悼了,接下来上场的是C语言内存函数memcpy,memmove,memset,memcmp
本文详细介绍了C语言中的四个内存操作函数:memcpy用于无重叠复制,memmove处理重叠内存,memset用于填充特定值,memcmp用于内存区域比较。通过实例展示了它们的用法和注意事项。
66 0
|
1月前
一刻也没有为它哀悼~接下来登场的是动态内存分配的malloc与realloc以及free函数
一刻也没有为它哀悼~接下来登场的是动态内存分配的malloc与realloc以及free函数
70 0