【C语言】memcpy,memmove,memcmp,memset函数详解

简介: 【C语言】memcpy,memmove,memcmp,memset函数详解

💐 🌸 🌷 🍀 🌹 🌻 🌺 🍁 🍃 🍂 🌿 🍄🍝 🍛 🍤

📃个人主页 阿然成长日记 👈点击可跳转

📆 个人专栏: 🔹数据结构与算法🔹C语言进阶

🚩 不能则学,不知则问,耻于问人,决无长进

🍭 🍯 🍎 🍏 🍊 🍋 🍒 🍇 🍉 🍓 🍑 🍈 🍌 🍐 🍍

🌸memcpy函数

#include

一、 memcpy函数的定义:

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

与strncmp区别是:参数方面:1.memcpy可以拷贝任意类型数据;2.num是字节数

二、memcpy函数的功能:

复制内存块

将字节数的值从源指向的位置直接复制到目标指向的内存块。

源指针和目标指针指向的对象的基础类型与此函数无关;结果是数据的二进制副本。

该函数不检查源中的任何终止空字符它总是==准确地复制字节数。

为避免溢出,目标和源参数指向的数组大小应至少为字节数,并且不应重叠(对于重叠的内存块,memmove 是一种更安全的方法)

三、memcpy函数模拟

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<assert.h>
void* my_memcpy(void* dest, void* src, size_t num)
{
  void* ret = dest;
  assert(dest);
  while (num--)
  {
    *(char*)dest = *(char*)src;
    dest = (char*)dest + 1;
    src = (char*)src + 1;
  }
  return ret;
}
int main()
{
  int arr1[] = { 0,1,2,3,4,5,6,7,8,9 };
  int arr2[20] = { 0 };
  my_memcpy(arr2, arr1, 40);
  int i = 0;
  for (i = 0; i < 20; i++)
  {
    printf("%d\n", arr2[i]);
  }
  return 0;
}

memcpy注意事项

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

2.这个函数在遇到 '\0' 的时候并不会停下来

3.如果source和destination有任何的重叠,复制的结果都是未定义的。

原因也很简单:如下代码

int arr1[] = { 0,1,2,3,4,5,6,7,8,9 };
  my_memcpy(arr1+2, arr1, 40);

给自己复制时,肯定时一位一位复制,把arr1[0]复制到arr+2(arr[2])位置时,arr1【2】的数值被覆盖为0,那么当我们继续复制时再取出arr[2]的值就是你之前已经复制过的了0,而不是原本的数值2,就不再是你想要复制的数据了。

4.

my_memcpy(arr2, arr1, 9);

这里我只复制前9个字节,可以发现打印出来了0,1,2.这是为什那么呢?

原因是:我们的vs编译器是小端存储(即,数据低位存到内存的高地址),

1,2,3在内存中的二进制存储为:

01 00 00 00|02 00 00 00|03 00 00 00 【一个00也就是一字节】

存储就9字节,正好把3 的关键位给复制进去了。

💭memmove函数

#include

一、memmove函数简介

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

参数与memcpy一样

与memcpy函数区别是,它通常被用在源空间和目标空间出现重叠时

二、memmove函数的模拟

1.两种情况

memomove复制时,有两种情况

1.dest地址

2.dest地址>src地址: 从后到前(右到左)

2模拟实现

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<assert.h>
void* my_memcpy(void* dest, void* src, size_t num)
{
  void* ret = dest;//保存初始位置地址
  assert(dest);//确保dest不为空
  if (dest < src)//分两种情况
  {
    while (num--)//情况一,从左到右复制
    {
      *(char*)dest = *(char*)src;
      dest = (char*)dest + 1;
      src = (char*)src + 1;
    }
  }
  else
  {
    while (num--)情况二:从右到左复制
    {
      *((char*)dest + num) = *((char*)src + num);
      //先强制转换成char型,再加上num个字节。
      //就是指向src,dest的末尾元素
    }
  }
  return ret;
}
int main()
{
  int arr1[] = { 0,1,2,3,4,5,6,7,8,9 };
  my_memcpy(arr1+5, arr1, 20);
  int i = 0;
  for (i = 0; i < 10; i++)
  {
    printf("%d\n", arr1[i]);
  }
  return 0;
}

💭memcmp函数

#include

1.memecmp函数介绍

1.1定义

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

参数:ptr1和ptr2都指向内存块的指针。

num:要比较的字节数

返回值:

返回一个整数值,该值指示内存块内容之间的关系:

返回值 表明
小于0 ptr2大(指向的第一个不相等字符块)
0 两个内存块的内容相等
大于0 ptr1大

1.2.功能

将 ptr1 指向的内存块的前 num 字节数与 ptr2 指向的第一个字节数进行比较,

如果它们都匹配,则返回零,

如果不匹配,则返回一个不同于零的值,表示哪个值更大。 请注意,与 strcmp 不同,该函数在找到空字符后不会停止比较。

✨memset函数

#include

1.memset函数介绍

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

参数: ptr;指向要填充的内存块的指针。

value:要设置的值。该值作为 int 传递,但该函数使用此值的无符号 char 转换填充内存块。

num:字节数

返回值:修改后的ptr

2.memset功能

3.memset使用

案例一:

#include<string.h>
int main()
{
  int arr[10] = { 0 };
  memset(arr, 1, 20);
  return 0;
 }

它是将每一个字节都赋值成1;

案例二:

#include<string.h>
int main()
{
  char arr[10] = { "hellloni"};
  memset(arr, 'x', 5);
  printf("%s", arr);
  return 0;
 }



相关文章
|
23天前
|
存储 Serverless C语言
【C语言基础考研向】11 gets函数与puts函数及str系列字符串操作函数
本文介绍了C语言中的`gets`和`puts`函数,`gets`用于从标准输入读取字符串直至换行符,并自动添加字符串结束标志`\0`。`puts`则用于向标准输出打印字符串并自动换行。此外,文章还详细讲解了`str`系列字符串操作函数,包括统计字符串长度的`strlen`、复制字符串的`strcpy`、比较字符串的`strcmp`以及拼接字符串的`strcat`。通过示例代码展示了这些函数的具体应用及注意事项。
|
26天前
|
存储 C语言
C语言程序设计核心详解 第十章:位运算和c语言文件操作详解_文件操作函数
本文详细介绍了C语言中的位运算和文件操作。位运算包括按位与、或、异或、取反、左移和右移等六种运算符及其复合赋值运算符,每种运算符的功能和应用场景都有具体说明。文件操作部分则涵盖了文件的概念、分类、文件类型指针、文件的打开与关闭、读写操作及当前读写位置的调整等内容,提供了丰富的示例帮助理解。通过对本文的学习,读者可以全面掌握C语言中的位运算和文件处理技术。
|
26天前
|
存储 C语言
C语言程序设计核心详解 第七章 函数和预编译命令
本章介绍C语言中的函数定义与使用,以及预编译命令。主要内容包括函数的定义格式、调用方式和示例分析。C程序结构分为`main()`单框架或多子函数框架。函数不能嵌套定义但可互相调用。变量具有类型、作用范围和存储类别三种属性,其中作用范围分为局部和全局。预编译命令包括文件包含和宏定义,宏定义分为无参和带参两种形式。此外,还介绍了变量的存储类别及其特点。通过实例详细解析了函数调用过程及宏定义的应用。
|
1月前
|
Linux C语言
C语言 多进程编程(三)信号处理方式和自定义处理函数
本文详细介绍了Linux系统中进程间通信的关键机制——信号。首先解释了信号作为一种异步通知机制的特点及其主要来源,接着列举了常见的信号类型及其定义。文章进一步探讨了信号的处理流程和Linux中处理信号的方式,包括忽略信号、捕捉信号以及执行默认操作。此外,通过具体示例演示了如何创建子进程并通过信号进行控制。最后,讲解了如何通过`signal`函数自定义信号处理函数,并提供了完整的示例代码,展示了父子进程之间通过信号进行通信的过程。
|
1月前
|
C语言
C语言 字符串操作函数
本文档详细介绍了多个常用的字符串操作函数,包括 `strlen`、`strcpy`、`strncpy`、`strcat`、`strncat`、`strcmp`、`strncpy`、`sprintf`、`itoa`、`strchr`、`strspn`、`strcspn`、`strstr` 和 `strtok`。每个函数均提供了语法说明、参数解释、返回值描述及示例代码。此外,还给出了部分函数的自实现版本,帮助读者深入理解其工作原理。通过这些函数,可以轻松地进行字符串长度计算、复制、连接、比较等操作。
|
1月前
|
SQL 关系型数据库 C语言
PostgreSQL SQL扩展 ---- C语言函数(三)
可以用C(或者与C兼容,比如C++)语言编写用户自定义函数(User-defined functions)。这些函数被编译到动态可加载目标文件(也称为共享库)中并被守护进程加载到服务中。“C语言函数”与“内部函数”的区别就在于动态加载这个特性,二者的实际编码约定本质上是相同的(因此,标准的内部函数库为用户自定义C语言函数提供了丰富的示例代码)
|
2月前
|
C语言
【C语言】字符串及其函数速览
【C语言】字符串及其函数速览
26 4
|
2月前
|
机器学习/深度学习 编译器 Serverless
C语言中函数
C语言中函数
22 0
|
2月前
|
存储 Serverless C语言
C语言中的标准库函数
C语言中的标准库函数
30 0
|
2月前
|
C语言
【C语言】epoll函数
【C语言】epoll函数
20 0