在 C 语言的编程世界里,内存操作是家常便饭,为了方便高效地操作内存,C 标准库提供了好几个实用的内存函数。今天,我就来给大家详细介绍这些内存函数,从最常见的`memcpy`、`memmove`、`memset`,到`memcmp`,不仅讲怎么用,还带你亲手模拟实现它们,新手友好,保证让你学完就能上手!
memcpy:内存块复制的“搬运工”
1. 函数原型
• `void *memcpy(void *dest, const void *src, size_t n);`
• 参数 dest 是目标内存块的指针,src 是源内存块的指针,n 是要复制的字节数。
• 返回值是 dest。
2. 功能
• `memcpy`就像是内存里的“搬运工”,从源内存块(src)开始向后复制 n 个字节的内容到目标内存块(dest)中,不关心内存里存的是啥数据类型(字符、整数等),只管按字节搬。
3. 注意事项
• 如果源内存块和目标内存块有重叠区域,`memcpy`的行为是未定义的(可能出错)。比如,从内存的第 100 字节开始复制到第 50 字节,且复制长度超过 50 字节,`memcpy`就可能把还没复制的数据给覆盖了。这种情况下,应该用`memmove`。
• 使用`memcpy`时,要确保源和目标内存块都是有效的,并且有足够的空间来容纳操作。
4. 使用示例
#include <stdio.h>
#include <string.h>
int main() {
char src[] = "hello world";
char dest[20];
memcpy(dest, src, sizeof(src)); // 复制整个 src 字符串
dest[sizeof(src) - 1] = '\0'; // 添加字符串结束符
printf("复制后的字符串:%s\n", dest);
return 0;
}
5. 模拟实现
• 思路:逐字节复制,从源内存块复制到目标内存块,复制 n 个字节。
#include <stdio.h>
void *my_memcpy(void *dest, const void *src, size_t n) {
char *d = (char *)dest;
const char *s = (const char *)src;
for (size_t i = 0; i < n; i++) {
d[i] = s[i];
}
return dest;
}
int main() {
char src[] = "hello world";
char dest[20];
my_memcpy(dest, src, sizeof(src));
dest[sizeof(src) - 1] = '\0';
printf("复制后的字符串:%s\n", dest);
return 0;
}
memmove:内存块复制的“快递员”(不怕重叠)
1. 函数原型
• `void *memmove(void *dest, const void *src, size_t n);`
• 参数和返回值与`memcpy`一样。
2. 功能
• `memmove`也是复制内存块的,但它比`memcpy`高级一点,能处理源和目标内存块有重叠的情况。它就像是“快递员”,不管源和目标是不是挨着,都能安全地把数据“快递”到目标地址。
3. 使用场景
• 当源和目标内存块有重叠时,比如在字符串中把后面的部分复制到前面,或者前面复制到后面,就用`memmove`。
4. 使用示例
#include <stdio.h>
#include <string.h>
int main() {
char str[] = "hello world";
memmove(str, str + 6, 5); // 把 "world" 复制到字符串开头
str[5] = '\0'; // 添加字符串结束符
printf("复制后的字符串:%s\n", str);
return 0;
}
5. 模拟实现
• 思路:先判断源和目标内存块的相对位置。如果源在目标后面,就从前往后复制;如果源在目标前面,就从后往前复制,避免数据被覆盖。
#include <stdio.h>
void *my_memmove(void *dest, const void *src, size_t n) {
char *d = (char *)dest;
const char *s = (const char *)src;
if (d < s) { // 源在目标后面,从前往后复制
for (size_t i = 0; i < n; i++) {
d[i] = s[i];
}
} else { // 源在目标前面或相同位置,从后往前复制
for (size_t i = n; i > 0; i--) {
d[i - 1] = s[i - 1];
}
}
return dest;
}
int main() {
char str[] = "hello world";
my_memmove(str, str + 6, 5);
str[5] = '\0';
printf("复制后的字符串:%s\n", str);
return 0;
}
memset:内存块设置的“涂色器”
1. 函数原型
• `void *memset(void *str, int c, size_t n);`
• 参数 str 是内存块的指针,c 是要设置的值(会被转换为 unsigned char),n 是要设置的字节数。
• 返回值是 str。
2. 功能
• `memset`就像是给内存块“涂色”,把内存块的前 n 个字节都设置成指定的值 c。常用来初始化内存,比如把内存全设置为 0。
3. 使用示例
#include <stdio.h>
#include <string.h>
int main() {
char str[20];
memset(str, 'A', 10); // 把 str 的前 10 个字节设置为 'A'
str[10] = '\0'; // 添加字符串结束符
printf("设置后的字符串:%s\n", str);
return 0;
}
4. 模拟实现
• 思路:逐字节设置,把内存块的前 n 个字节都设置为 c 的值(转换为 unsigned char)。
#include <stdio.h>
void *my_memset(void *str, int c, size_t n) {
unsigned char *s = (unsigned char *)str;
unsigned char value = (unsigned char)c;
for (size_t i = 0; i < n; i++) {
s[i] = value;
}
return str;
}
int main() {
char str[20];
my_memset(str, 'A', 10);
str[10] = '\0';
printf("设置后的字符串:%s\n", str);
return 0;
}
memcmp:内存块比较的“裁判员”
1. 函数原型
• `int memcmp(const void *str1, const void *str2, size_t n);`
• 参数 str1 和 str2 是两个内存块的指针,n 是要比较的字节数。
• 返回值:
• 如果两个内存块的前 n 个字节相等,返回 0。
• 如果 str1 小于 str2,返回负数。
• 如果 str1 大于 str2,返回正数。
2. 功能
• `memcmp`就像是在比武场上当“裁判员”,逐字节比较两个内存块的前 n 个字节,判断它们的大小关系。
3. 使用示例
#include <stdio.h>
#include <string.h>
int main() {
char str1[] = "hello";
char str2[] = "hella";
int result = memcmp(str1, str2, 5);
if (result == 0) {
printf("两个内存块的前 5 个字节相等\n");
} else if (result < 0) {
printf("str1 的前 5 个字节小于 str2\n");
} else {
printf("str1 的前 5 个字节大于 str2\n");
}
return 0;
}
4. 模拟实现
• 思路:逐字节比较,如果找到不同的字节就返回它们的差值,比较完 n 个字节都相同就返回 0。
#include <stdio.h>
int my_memcmp(const void *str1, const void *str2, size_t n) {
const unsigned char *s1 = (const unsigned char *)str1;
const unsigned char *s2 = (const unsigned char *)str2;
for (size_t i = 0; i < n; i++) {
if (s1[i] != s2[i]) {
return s1[i] - s2[i];
}
}
return 0;
}
int main() {
char str1[] = "hello";
char str2[] = "hella";
int result = my_memcmp(str1, str2, 5);
if (result == 0) {
printf("两个内存块的前 5 个字节相等\n");
} else if (result < 0) {
printf("str1 的前 5 个字节小于 str2\n");
} else {
printf("str1 的前 5 个字节大于 str2\n");
}
return 0;
}
总结
今天,咱们把 C 语言里超实用的内存函数`memcpy`、`memmove`、`memset`和`memcmp`一网打尽啦!从`memcpy`的内存块复制,到`memmove`的重叠区域复制,再到`memset`的内存初始化,以及`memcmp`的内存比较,新手友好,这些函数在日常编程里超常用,学会它们,内存操作不再是难题!希望大家能多练练,把每个函数都玩得明明白白。
宝子们,今天的内容是不是让你对 C 语言的内存函数有了全新的认识?有没有哪个函数的模拟实现让你眼前一亮,或者曾经困扰你的地方现在豁然开朗?快来评论区分享你的学习心得或者疑问吧!说不定你的分享就能帮到其他小伙伴,大家一起进步,下次咱们继续在 C 语言的编程之旅中探索更多宝藏知识!