当前位置: 首页 > news >正文

C语言自学--C语⾔内存函数

目录

1、memcpy 的使用与模拟实现

1.1、memcpy 的使用

1.2、memcpy 的模拟实现

2、memmove 的使用与模拟实现

2.1、memmove 的使用

2.2、memmove 的模拟实现

3、memset 函数的使用

3.1、memset 函数的基本介绍

3.2、memset 的常见用途

3.3、注意事项

3.4、示例代码

3.5、总结

4、memcmp 函数的使用

4.1、memcmp 函数的基本用法

4.2、示例代码

4.3、注意事项


1、memcpy 的使用与模拟实现

1.1、memcpy 的使用

        memcpy 是 C 标准库中的一个函数,用于将源内存区域的内容复制到目标内存区域。其函数原型如下:

void *memcpy(void *dest, const void *src, size_t n);
  • dest:目标内存区域的指针。
  • src:源内存区域的指针。
  • n:要复制的字节数,遇到‘\0’的时候并不会停下来,也就是说,n是多少就复制多少字节。

注意事项:

  • 目标内存区域必须足够大,以避免缓冲区溢出。
  • 源和目标内存区域不应重叠,否则行为未定义。若存在重叠,应使用 memmove
#include <stdio.h>
#include <string.h>int main() {char src[] = "Hello, World!";char dest[20];memcpy(dest, src, strlen(src) + 1); // 复制字符串,包括空字符printf("Copied string: %s\n", dest);return 0;
}
#include <stdio.h>int main()
{int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };int arr2[20] = { 0 };memcpy(arr2,arr1,20);return 0;
}

在arr数组中一个int元素占4个字节,20就是复制五个元素到arr2中。

1.2、memcpy 的模拟实现
//memcpy的模拟实现
#include <stdio.h>
#include <assert.h>
void* my_memcpy(void* dest, const void* src,size_t num)
{assert(dest && src);void* ret = dest;while (num--){*(char*)dest = *(char*)src;dest = (char*)dest + 1;//不能写为dest++,原因在下方给出!!src = (char*)src + 1;	}return ret;
}int main()
{int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };int arr2[20] = { 0 };my_memcpy(arr2, arr1, 8);for (int i = 0; i < 10; i++){printf("%d ",arr2[i]);}return 0;
}

为什么不能写为dest++呢?

*(char*)dest = *(char*)src;
dest = (char*)dest + 1;//不能写为dest++,原因在下方给出!!
src = (char*)src + 1;

指针运算的核心差异

  1. 类型决定步长 (int*)dest + 1: 将dest转换为int类型后,+1操作会移动sizeof(int)个字节(通常为4字节)。 示例:int指针从地址0x1000递增到0x1004。 dest++(void类型): void作为通用指针,编译器无法确定增量步长,因此直接报错(C/C++禁止void*的算术运算)。

  2. void的特殊性质 void表示"无类型指针",编译器无法解析++操作(缺乏类型信息)。 必须显式转换为具体类型(如int*、char*)才能执行指针运算。

int arr[10];
void* p = arr;// 合法:明确按int步长移动
p = (int*)p + 1;  // 移动4字节// 非法:void*无法自增
p++;  // 编译错误

2、memmove 的使用与模拟实现

2.1、memmove 的使用

        memmove 是 C 标准库中的一个函数,用于复制内存块。其原型如下

void* memmove(void* dest, const void* src, size_t n);
  • dest:目标内存地址。
  • src:源内存地址。
  • n:需要复制的字节数。

        memmove 的特点是可以处理内存重叠的情况。当源内存和目标内存有重叠时,memmove 会确保数据正确复制,而不会因覆盖导致错误。

#include <stdio.h>
#include <string.h>int main() {char str[] = "Hello, World!";memmove(str + 7, str, 5); // 将 "Hello" 复制到 "World!" 的位置printf("%s\n", str);      // 输出: Hello, Hello!return 0;
}
2.2、memmove 的模拟实现
void * memmove ( void * dst, const void * src, size_t count){void * ret = dst;if (dst <= src || (char *)dst >= ((char *)src + count)) {/** Non-Overlapping Buffers* copy from lower addresses to higher addresses*/while (count--) {*(char *)dst = *(char *)src;dst = (char *)dst + 1;src = (char *)src + 1;}}else {/** Overlapping Buffers* copy from higher addresses to lower addresses*/dst = (char *)dst + count - 1;src = (char *)src + count - 1;while (count--) {*(char *)dst = *(char *)src;dst = (char *)dst - 1;src = (char *)src - 1;}}return(ret);}

3、memset 函数的使用

3.1、memset 函数的基本介绍

memset 是 C 标准库中的一个函数,用于将指定内存区域的前 n 个字节设置为特定值。其原型定义在 <string.h> 头文件中:

void *memset(void *s, int c, size_t n);
  • s:指向要填充的内存区域的指针。
  • c:要填充的值(以 int 形式传递,但实际填充时会被转换为 unsigned char)。
  • n:要填充的字节数。
3.2、memset 的常见用途

初始化数组或结构体

常用于将数组或结构体的内存区域初始化为 0 或其他特定值:

char buffer[100];
memset(buffer, 0, sizeof(buffer)); // 将 buffer 全部初始化为 0
3.3、注意事项

填充值的行为

memset 按字节填充,因此对非字符类型的数组填充时需谨慎。例如,将 int 数组填充为 1 时,每个 int 的 4 字节会被设置为 0x01,而非整体值为 1:

int arr[10];
memset(arr, 1, sizeof(arr)); // 每个 int 的值为 0x01010101,而非 100000001     00000001     00000001     00000001   //一个int四个字节,每个字节八位
0000 0001    0000 0001    0000 0001   0000 0001  //二进制转换十六进制,四位一组0    1       0    1       0    1      0     1  //memset是每个字节都要改

性能优化

memset 通常由编译器优化为高效的底层指令(如 rep stosb),适合大规模内存初始化。但对于小内存块,直接赋值可能更快。

3.4、示例代码

初始化字符数组

#include <stdio.h>
#include <string.h>int main() {char str[50] = "Hello, World!";printf("Before memset: %s\n", str);memset(str, '*', 5); // 将前 5 个字符替换为 '*'printf("After memset: %s\n", str);return 0;
}

输出结果

Before memset: Hello, World!
After memset: *****, World!

结构体初始化

#include <stdio.h>
#include <string.h>typedef struct {int id;char name[20];
} Person;int main() {Person p;memset(&p, 0, sizeof(Person)); // 将结构体所有成员初始化为 0printf("ID: %d, Name: %s\n", p.id, p.name);return 0;
}
3.5、总结

  memset 是高效的内存初始化工具,但需注意其按字节填充的特性。适用于字符数组、清空内存或结构体初始化等场景,但对于非字符类型的数据初始化需谨慎使用。


4、memcmp 函数的使用

4.1、memcmp 函数的基本用法

  memcmp 是 C/C++ 标准库中的内存比较函数,用于比较两块内存区域的内容是否一致。

函数原型:

int memcmp(const void *s1, const void *s2, size_t n);  
  • 参数

    • s1:指向第一块内存区域的指针。
    • s2:指向第二块内存区域的指针。
    • n:需要比较的字节数。
  • 返回值

    • 返回值为 0,表示两块内存区域内容完全相同。
    • 返回值 < 0,表示 s1 在第一个不匹配字节处的值小于 s2
    • 返回值 > 0,表示 s1 在第一个不匹配字节处的值大于 s2
4.2、示例代码
#include <stdio.h>  
#include <string.h>  int main() {  char buffer1[] = "Hello";  char buffer2[] = "World";  int result;  result = memcmp(buffer1, buffer2, 5);  if (result == 0) {  printf("内容相同\n");  } else if (result < 0) {  printf("buffer1 小于 buffer2\n");  } else {  printf("buffer1 大于 buffer2\n");  }  return 0;  
}  
4.3、注意事项
  • 比较时按字节逐个进行,直到发现不匹配或比较完 n 个字节。
  • 适用于任意数据类型(如结构体、数组等),但需确保内存区域合法且可读。
  • 不检查字符串结束符(\0),与 strcmp 不同。

http://www.dtcms.com/a/395404.html

相关文章:

  • 磁带记录仪:从磁带到数字的数据存储之旅
  • 【运维】Ubuntu上WebDAV挂载与自动同步完整指南
  • Ubuntu之旅-04 Docker
  • python(73) 引用.dll文件并调用函数
  • Chrome 学习小记5——demo:(动态壁纸基础)
  • 手写 Android Dex VMP 壳:自定义虚拟机 + 指令解释执行全流程
  • 【Netty】创建一个 SSL 处理器,实现客户端与服务器之间的安全通信
  • 13 Python数据结构与算法
  • 爱:宇宙的心跳
  • Python字节数据写入文本文件完全指南:从基础到高级实战
  • 零基础Windows10安装LLVM
  • selenium三种等待方式详解
  • Leetcode总结速记
  • 手写 Android Dex VMP 壳:指令流 AES 加密 + 动态加载全流程
  • 视频融合平台EasyCVR国标GB28181视频诊断功能详解与实践
  • ORACLE adg 备库也能单独提取AWR报告
  • Angular由一个bug说起之十九:Angular 实现可拓展 Dropdown 组件
  • Kafka核心架构与高效消息处理指南
  • flink1.18配置多个上游source和下游sink
  • 快速查看自己电脑的ip地址:一个命令见本机私网ip,一步查询本地网络公网ip,附内网ip让外网访问的通用方法
  • 插件化(Plugin)设计模式——Python 的动态导入和参数解析库 argparse 的高级用法
  • 【JavaSE】【网络原理】UDP和TCP原理
  • 高防IP真的能抵御DDoS攻击吗?
  • 93. 复原 IP 地址
  • 智能排班系统,促进人岗匹配提升人效
  • PostgreSQL介绍和PostgreSQL包安装
  • 分享“泰迪杯”数据挖掘挑战赛全新升级——赛题精准对标,搭建 “白名单” 赛事进阶通道
  • 对接文档:快递鸟取件码API,实现物流末端服务自动化
  • GIS学习:GIS认知与开发初步入门
  • 9. NVME与SSD之间的通信