第18讲:C语言内存函数
📚 第18讲:C语言内存函数
深入理解底层内存操作,掌握高效、安全的数据拷贝与比较技术!
📂 目录
memcpy
的使用与模拟实现 🧩memmove
的使用与模拟实现 🔄memset
函数的使用 🎨memcmp
函数的使用 ⚖️
📖 正文开始
在C语言中,除了字符串操作函数外,还有一组内存函数,它们不关心数据类型,而是以字节为单位直接操作内存。这些函数定义在 <string.h>
头文件中,适用于任意类型的数据块操作。
memcpy
的使用与模拟实现 🧩
void *memcpy(void *destination, const void *source, size_t num);
🔹 特性说明
- 从
source
指向的内存位置开始,复制num
个字节到destination
。 - 不会因遇到
'\0'
而停止。 - 如果
source
和destination
指向的内存区域有重叠,行为是未定义的(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
(按字节填充)。 - 常用于初始化数组、结构体等。
value
是int
类型,但只使用其低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);
🔹 特性说明
- 比较从
ptr1
和ptr2
开始的num
个字节。 - 按字节进行无符号比较。
- 返回值:
> 0
:ptr1
大于ptr2
== 0
:前num
字节完全相同< 0
:ptr1
小于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代码!
下节我们将学习动态内存管理,敬请期待!💪