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

第18讲:C语言内存函数

📚 第18讲:C语言内存函数

深入理解底层内存操作,掌握高效、安全的数据拷贝与比较技术!


📂 目录

  1. memcpy 的使用与模拟实现 🧩
  2. memmove 的使用与模拟实现 🔄
  3. memset 函数的使用 🎨
  4. memcmp 函数的使用 ⚖️

📖 正文开始

在C语言中,除了字符串操作函数外,还有一组内存函数,它们不关心数据类型,而是以字节为单位直接操作内存。这些函数定义在 <string.h> 头文件中,适用于任意类型的数据块操作。


memcpy 的使用与模拟实现 🧩

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

🔹 特性说明

  • source 指向的内存位置开始,复制 num 个字节destination
  • 不会因遇到 '\0' 而停止。
  • 如果 sourcedestination 指向的内存区域有重叠,行为是未定义的(undefined behavior)。

适用场景:源和目标内存不重叠时的高效拷贝。

✅ 示例:整型数组拷贝
#include <stdio.h>
#include <string.h>int main() {int arr1[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};int arr2[10] = {0};// 拷贝前20个字节(5个int)memcpy(arr2, arr1, 20);for (int i = 0; i < 10; i++) {printf("%d ", arr2[i]);}printf("\n");return 0;
}

📌 输出:1 2 3 4 5 0 0 0 0 0


🔧 memcpy 模拟实现

#include <stdio.h>
#include <assert.h>void *my_memcpy(void *dst, const void *src, size_t count) {void *ret = dst;assert(dst != NULL);assert(src != NULL);// 逐字节拷贝:从低地址向高地址while (count--) {*(char *)dst = *(char *)src;dst = (char *)dst + 1;src = (char *)src + 1;}return ret;
}int main() {int arr1[] = {10, 20, 30, 40};int arr2[4] = {0};my_memcpy(arr2, arr1, sizeof(arr1));for (int i = 0; i < 4; i++) {printf("%d ", arr2[i]);}printf("\n");return 0;
}

📌 输出:10 20 30 40

⚠️ 注意:此函数不能处理内存重叠!重叠场景请使用 memmove


memmove 的使用与模拟实现 🔄

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

🔹 特性说明

  • 功能与 memcpy 类似,但可以正确处理源和目标内存区域重叠的情况
  • 是处理重叠内存拷贝的安全选择
✅ 示例:数组内部移动(内存重叠)
#include <stdio.h>
#include <string.h>int main() {int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};// 将前5个元素(20字节)向前移动2个位置memmove(arr + 2, arr, 20);for (int i = 0; i < 10; i++) {printf("%d ", arr[i]);}printf("\n");return 0;
}

📌 输出:1 2 1 2 3 4 5 8 9 10

🔍 解析

  • 原数组:[1,2,3,4,5,6,7,8,9,10]
  • arr[0]~arr[4] 拷贝到 arr[2]~arr[6]
  • 使用 memmove 可避免因重叠导致的数据覆盖错误。

🔧 memmove 模拟实现

#include <assert.h>void *my_memmove(void *dst, const void *src, size_t count) {void *ret = dst;assert(dst != NULL);assert(src != NULL);if (dst <= src || (char *)dst >= ((char *)src + count)) {// ✅ 情况1:无重叠 或 重叠但目标在源之后// 从低地址向高地址拷贝while (count--) {*(char *)dst = *(char *)src;dst = (char *)dst + 1;src = (char *)src + 1;}} else {// ✅ 情况2:重叠且目标在源之前// 从高地址向低地址拷贝,避免覆盖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;
}int main() {char str[] = "hellohello";my_memmove(str + 5, str, 5);  // 重叠拷贝printf("Result: %s\n", str);  // 输出: hellohelloreturn 0;
}

关键点:通过判断内存地址关系,选择正向或反向拷贝,确保数据安全。


memset 函数的使用 🎨

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

🔹 特性说明

  • ptr 指向的内存区域的num 个字节,设置为 value(按字节填充)。
  • 常用于初始化数组、结构体等。
  • valueint 类型,但只使用其低8位(一个字节)。
✅ 示例:字符数组填充
#include <stdio.h>
#include <string.h>int main() {char str[] = "hello world";memset(str, 'x', 6);  // 前6个字符设为 'x'printf("Result: %s\n", str);  // 输出: xxxxxxworldreturn 0;
}
✅ 示例:整型数组初始化为0
#include <stdio.h>
#include <string.h>int main() {int arr[5];memset(arr, 0, sizeof(arr));  // 全部设为0for (int i = 0; i < 5; i++) {printf("%d ", arr[i]);}printf("\n");return 0;
}

📌 输出:0 0 0 0 0

⚠️ 注意memset 是按字节设置的。若想将 int 数组设为 -1,可以:

memset(arr, -1, sizeof(arr)); // 每个字节都是 0xFF,int 变为 -1

memcmp 函数的使用 ⚖️

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

🔹 特性说明

  • 比较从 ptr1ptr2 开始的 num 个字节
  • 按字节进行无符号比较
  • 返回值:
    • > 0ptr1 大于 ptr2
    • == 0:前 num 字节完全相同
    • < 0ptr1 小于 ptr2
✅ 示例:比较两个缓冲区
#include <stdio.h>
#include <string.h>int main() {char buffer1[] = "DWgaOtP12df0";char buffer2[] = "DWGAOTP12DF0";int n;// 比较整个字符串(包含 '\0')n = memcmp(buffer1, buffer2, sizeof(buffer1));if (n > 0) {printf("'%s' is greater than '%s'.\n", buffer1, buffer2);} else if (n < 0) {printf("'%s' is less than '%s'.\n", buffer1, buffer2);} else {printf("'%s' is the same as '%s'.\n", buffer1, buffer2);}return 0;
}

📌 输出:'DWgaOtP12df0' is greater than 'DWGAOTP12DF0'.

🔍 解析:比较是逐字节进行的。第一个不同字符是 'g' vs 'G',由于 'g' > 'G'(ASCII值),所以返回正值。

✅ 示例:比较结构体或任意数据块
#include <stdio.h>
#include <string.h>struct Data {int id;float score;
};int main() {struct Data d1 = {1001, 89.5f};struct Data d2 = {1001, 89.5f};if (memcmp(&d1, &d2, sizeof(struct Data)) == 0) {printf("Two data structs are identical.\n");} else {printf("Data structs differ.\n");}return 0;
}

📌 输出:Two data structs are identical.


✅ 核心知识点总结

函数功能是否支持重叠关键点
memcpy内存拷贝❌ 不支持高效,但重叠时行为未定义
memmove内存移动✅ 支持安全处理重叠,稍慢
memset内存设置按字节填充,常用于初始化
memcmp内存比较按字节比较,返回差值

🎯 掌握这些内存函数,你就能像操作系统一样直接操控内存,写出更高效、底层的C代码!
下节我们将学习动态内存管理,敬请期待!💪

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

相关文章:

  • 外贸网站如何做推广论坛网站 备案
  • 深圳网站建设首选h5case是什么网站
  • Matlab的交通标志定位实现
  • 课堂网站开发企业管理培训班哪个好
  • 记录一个自动学习的脚本开发过程
  • h5游戏免费下载:一起蛙蛙跳
  • chrome中的axure插件提示无法不受支持
  • 石家庄住房城乡建设厅网站著名企业vi设计
  • 深圳做网站的公司排名开个人网站如何赚钱
  • centos 生产环境搭建最佳实践 (一)
  • RocketMQ 实战:马拉松系统异步化与延时任务落地(含死信队列处理)
  • 通达信指标平台
  • 网站建设及推广培训网站备案查询站长工具
  • MATLAB2025B版本新特点
  • Node.js使用Express+SQLite实现登录认证
  • 仿百度百科网站源码设计类专业学校有哪些
  • 重庆建站多少钱一年工业产品设计培训
  • 【IEEE出版 | 早鸟优惠本周截止】人工智能驱动图像处理与计算机视觉技术国际学术研讨会 (AIPCVT 2025)
  • 网站开发案例教程东营网站建设服务商
  • 基于微信小程序的垃圾分类管理系统【2026最新】
  • SSM高校教室申请管理系统yf80k(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
  • 创建一个SpringBoot项目(连接数据库)
  • 飞沐网站设计大鹏网站建设建站好不好
  • 淮南专业网站建设怎样保存网站资料 做证据
  • 如何在WPF中实现ComboBox多选
  • 单北斗GNSS变形监测是什么?主要用于大坝及桥梁安全监测吗?
  • 网站建设公司的服务器建设网站申请书
  • 如何加强省市级门户网站的建设太原网站优化服务
  • YOLO-V1 与 YOLO-V2 核心笔记
  • 公司做网站的价格江阴宁波网站建设那家好