内存操作函数

简介: 内存操作函数

一、memcpy函数


函数模型:



函数参数:


参数 意义
destination 指向目的地地址的指针,类型转换为 void* 类型的指针。
source 指向要复制的数据源的指针,类型转换为 const void* 类型的指针。
num 要复制的字节数


函数头文件:


#include <string.h>


函数功能:


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


注意:


要保证目的地址存的下源地址的内容,要守规矩哦!


1.为什么有了strcpy函数还要有memcpy函数呢?


因为strcpy函数是字符串拷贝,包括strncpy函数也是一样,只能拷贝字符串,对于其它类型,比如整形的拷贝就无能为力.


2.为什么要设置为void*类型?


如果看过前面qsort函数的模拟,这里应该也不难理解,因为要拷贝的类型是未知的,为了能够接收所有类型,所以设置为void*,使用时强制转换为char*类型,然后按字节个数拷贝即可.


函数的应用:


1.将arr2数组的前三个元素拷贝到arr1数组的前三个位置.


2.将字符串str2全部除了’\0’以外,拷贝到str1字符串.


#include <stdio.h>
#include <string.h>
int main()
{
  int arr1[10] = { 6,6,6,6,6,6,6,6,6,6 };
  int arr2[] = { 1,2,3,4,5,6,7,8 };
  int arr2sz= sizeof(arr2) / sizeof(arr2[0]);
  char str1[] = "XXXXXXXXXXXXXXXX";
  char str2[] = "Hello CSDN!";
  int str2sz= sizeof(str2) / sizeof(str2[0]);
  memcpy(arr1, arr2, sizeof(int) * 3);
  for (int i = 0; i < 10; i++)
  {
    printf("%d ", arr1[i]);
  }
  printf("\n");
  memcpy(str1, str2, sizeof(char) * str2sz - 1);//-1是因为这里使用的是sizeof()函数计算的长度,会包括\0
  printf("%s", str1);
  printf("\n");
  return 0;
}


运行结果:


1 2 3 6 6 6 6 6 6 6
Hello CSDN!XXXXX


函数的模拟实现:


#include<assert.h>
void* my_memcpy(void* destination, const void* source, size_t num)
{
  assert(destination);
  assert(source);
  while (num--)
  {
  //void*类型不可直接使用,要强制转化
    *(char*)destination = *(char*)source;//*是为了找到该地址所对应的字符串
    ((char*)destination)++;//指针分别往后走,所以不需要解引用
    ((char*)source)++;
  }
}


思考:


memcpy函数可以拷贝内存重叠的地址吗?


即source和destination有重叠的时候.(可以试试).


二、memmove函数


函数模型:



函数参数:


参数 意义
destination 指向目的地地址的指针,类型转换为 void* 类型的指针。
source 指向要复制的数据源的指针,类型转换为 const void* 类型的指针。
num 要复制的字节数


函数作用:


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

的。


如果源空间和目标空间出现重叠,就得使用memmove函数处理,其实在有的编译器中,对于memcpy函数也进行了优化,也是允许内存重叠的.


但牛牛认为,还是有必要掌握这种更"稳妥"的函数的.


情况1



这种情况我们可以正常的从前向后(前->后) 拷贝.


即:先将6拷贝至2位置,再讲7拷贝至3位置……



这种情况我们使用从从前向后(前->后)拷贝则达不到我们的要求.


如果我们先将6拷贝至8处,7拷贝至9处,则原来的8 9都被修改了.


这时我们需要从后往前(后->前)拷贝.


即先将11拷贝至13处,再将9拷贝至12处……



其实这种情况并不是内存地址重叠,目的地址出现在前面也是一样的,都是可以从前向后(前->后)拷贝和从后往前(后->前)拷贝皆可.


函数模拟实现


#include <stdio.h>
#include<assert.h>
void* my_memmove(void* destination, const void* source, size_t num)
{
  void* ret = destination;//保留目的地原来的首地址
  assert(destination && source);//防止传错地址
  if (destination < source)//情况1时,目的地址的首地址小于源地址首地址
  {
    //前-->后
    while (num--)
    {
      *(char*)destination = *(char*)source;
      ((char*)destination)++;
      ((char*)source)++;
    }
  }
  else
  {
    //后->前
    while (num--)
    {
      *((char*)destination + num) = *((char*)source + num);//注意,这里如果以destination为1的偏移量,+num则是目的地地址的最后一个元素的地址.
    }
  }
  return ret;
}


代码测试:


情况1;


int main()
{
  int arr[] = { 1,2,3,4,5,6,7,8,9,11,12,13 };
  //情况1
  my_memmove(arr + 1, arr + 5, sizeof(int) * 5);
  int sz= sizeof(arr) / sizeof(arr[0]);
  for (int i = 0; i < sz; i++)
  {
    printf("%d ", arr[i]);
  }
  return 0;
}


运行结果:


1 6 7 8 9 11 7 8 9 11 12 13


情况2:


int main()
{
  int arr[] = { 1,2,3,4,5,6,7,8,9,11,12,13 };
  //情况1
  my_memmove(arr +7, arr + 5, sizeof(int) * 5);
  int sz = sizeof(arr) / sizeof(arr[0]);
  for (int i = 0; i < sz; i++)
  {
    printf("%d ", arr[i]);
  }
  return 0;
}


运行结果:


1 2 3 4 5 6 7 6 7 8 9 11


三、memcmp函数


函数模型:



函数参数:


参数 意义
ptr1 指向要比较的内容1,指针
ptr2 指向要比较的内容2,指针
num 要比较的字节个数


函数头文件:


#include <string.h>


函数功能


比较从ptr1和ptr2指针开始的num个字节.


注意与strcmp函数区分:


strcmp函数:用于比较字符串是否相等,只用于比较字符


memcmp:按字节比较,两个指针所指向的内容是否相等.可用于比较不同类型的元素,但是是按字节比较.


返回值 意义
<0 第一个不想等的字节中的值的str1的值小于str2中的值(arr1<arr2)
0 两个指针的内容相等
>0 第一个不相等的字节的str1的值大于于str2中的值(arr1>arr2


函数应用:


试着猜一下这段代码的值?(vs2022环境(小端))


//memcmp函数模拟
#include <stdio.h>
#include <string.h>
int main()
{
  int arr1[] = { 1,4,7,255 };
  int arr2[] = { 1,4,7,511 };
  int ret=memcmp(arr1, arr2, 13);
  printf("%d", ret);
  return 0;
}


答案:


0


解析:


首先这里是小端存储模式.则这两个数组在内存中存储的是:


arr1 :01 00 00 00 04 00 00 00 07 00 00 00 FF 00 00 00 (16进制,两位代表一个字节)

arr2 :01 00 00 00 04 00 00 00 07 00 00 00 FF 10 00 00


很明显,这里前四个元素(1,4,7)是相等的,而元素255和元素511则是第一个字节的内容相等,所以当比较的元素是[0,13]时,memcmp函数会认为这两个指针所指向的内容是相同的,故返回值是0.


可以试着改成14字节,返回值会是-1,因为第14个字节,arr1是00.arr2是1,则arr1<arr2;


模拟实现


#include<assert.h>
int my_memcmp(const void* ptr1, const void* ptr2, size_t num)
{
  assert(ptr1 && ptr2);
  while (num--)//比较num个字节
  {
    if (*(char*)ptr1 == *(char*)ptr2)//相等继续往后比较
    {
      ((char*)ptr1)++;
      ((char*)ptr2)++;
    }
    else if (*(char*)ptr1 > *(char*)ptr2)//str1大则返回大于0的数
    {
      return 1;
    }
    else//str2大返回小于0的数
    {
      return -1;
    }
  }
  return 0;//比完了num个字节都相等则返回0
}


四、memset函数


函数模型:



头文件:


#include <string.h>


函数参数


参数 意义
ptr 指向要设置内容的空间
value 要设置的值,虽然是整形类型,但是也可以是字符,字符会转化为对应的ASCII码值
num 要设置空间内容的字节个数


函数功能:


将ptr所指向的空间,的num个字节设置为value值,注意这里也是按字节设置.


示例:


#include <stdio.h>
#include <string.h>
int main()
{
  int arr[5] = { 0 };
  memset(arr, 1, 20);
  for (int i = 0; i < 5; i++)
  {
    printf("%d ", arr[i]);
  }
  return 0;
}


结果会是下面这个吗?


1 1 1 1 1


正确答案:


16843009 16843009 16843009 16843009 16843009


为什么呢?


我们可以试着通过调试找到答案.



执行语句memset(arr, 1, 40);后



很显然,这里是将20个字节设置为了1,而一个整形占4个字节;



那么怎样才可以将每个元素都设置为1呢?


#include <stdio.h>
#include <string.h>
int main()
{
  int arr[5] = { 0 };
  for (int i = 0; i < 5; i++)
  {
    memset(arr+i, 1, 1);
  }
  for (int i = 0; i < 5; i++)
  {
    printf("%d ", arr[i]);
  }
  return 0;
}


其实这样才能达到我们想要的结果,这里是将一个字节设置为1,然后跳过四个字节(下一个元素),再将这个元素的首字节设置为1.


但是这样是不是有点太麻烦了,所以一般memset函数一般不会这么用,一般memset函数用来将一段空间的元素按字节都初始化为0,在后面我们用到malloc函数向内存申请空间时,得到的空间里面存放的值都是随机值,这时我们可以使用它来帮助我们完成初始化操作.


目录
相关文章
|
2月前
|
C语言 C++
C语言 之 内存函数
C语言 之 内存函数
42 3
|
25天前
|
存储 缓存 算法
【C语言】内存管理函数详细讲解
在C语言编程中,内存管理是至关重要的。动态内存分配函数允许程序在运行时请求和释放内存,这对于处理不确定大小的数据结构至关重要。以下是C语言内存管理函数的详细讲解,包括每个函数的功能、标准格式、示例代码、代码解释及其输出。
54 6
|
2月前
|
程序员 C++ 容器
在 C++中,realloc 函数返回 NULL 时,需要手动释放原来的内存吗?
在 C++ 中,当 realloc 函数返回 NULL 时,表示内存重新分配失败,但原内存块仍然有效,因此需要手动释放原来的内存,以避免内存泄漏。
|
2月前
|
存储 程序员 编译器
C语言——动态内存管理与内存操作函数
C语言——动态内存管理与内存操作函数
|
2月前
|
编译器 C语言 C++
详解C/C++动态内存函数(malloc、free、calloc、realloc)
详解C/C++动态内存函数(malloc、free、calloc、realloc)
399 1
|
2月前
|
程序员 C语言
C语言内存函数精讲
C语言内存函数精讲
|
2月前
|
存储 编译器 C++
【C++】掌握C++类的六个默认成员函数:实现高效内存管理与对象操作(二)
【C++】掌握C++类的六个默认成员函数:实现高效内存管理与对象操作
|
2月前
|
存储 C语言
【c语言】字符串函数和内存函数
本文介绍了C语言中常用的字符串函数和内存函数,包括`strlen`、`strcpy`、`strcat`、`strcmp`、`strstr`、`strncpy`、`strncat`、`strncmp`、`strtok`、`memcpy`、`memmove`和`memset`等函数的使用方法及模拟实现。文章详细讲解了每个函数的功能、参数、返回值,并提供了具体的代码示例,帮助读者更好地理解和掌握这些函数的应用。
41 0
|
2月前
|
C语言 C++
c语言回顾-内存操作函数
c语言回顾-内存操作函数
48 0
|
2月前
|
存储 C语言 C++
来不及哀悼了,接下来上场的是C语言内存函数memcpy,memmove,memset,memcmp
本文详细介绍了C语言中的四个内存操作函数:memcpy用于无重叠复制,memmove处理重叠内存,memset用于填充特定值,memcmp用于内存区域比较。通过实例展示了它们的用法和注意事项。
83 0

热门文章

最新文章