- 博客主页:向不悔
- 本篇专栏:[C]
- 您的支持,是我的创作动力。
文章目录
- 0、总结
- 1、memcpy使用和模拟实现
- 1.1 memcpy的使用
- 1.2 memcpy的模拟实现
- 2、memmove使用和模拟实现
- 2.1 memmove的使用
- 2.2 memmove的模拟实现
- 3、memset函数的使用
- 3.1 memset的使用
- 3.2 memset的模拟实现
- 4、memcmp函数的使用
- 4.1 memcmp的使用
- 4.2 memcmp的模拟实现
0、总结
在C语言中,有一些常用的内存操作函数,它们在处理内存数据时非常实用。下面将详细介绍memcpy
、memmove
、memset
和memcmp
这四个函数的使用方法及模拟实现。
1、memcpy使用和模拟实现
1.1 memcpy的使用
介绍:
- 头文件:
string.h
- 函数原型:
void* memcpy(void* destination, const void* source, size_t num);
- 作用:从
source
的位置开始向后复制num
个字节的数据到destination
指向的内存位置。 - 参考:https://legacy.cplusplus.com/reference/cstring/memcpy/
总结如下:
- 源和目标内存块不能重叠,否则会导致未定义行为。
- 不检查源数据中的终止符,总是复制指定的字节数。
- 目标内存空间需要足够大以容纳复制的数据,否则会导致内存溢出。
1.2 memcpy的模拟实现
#include <stdio.h>
#include <assert.h> // 用于 assertvoid* my_memcpy(void* dst, const void* src, size_t count) {// 保存目标地址,方便最后返回void* ret = dst;// 断言确保目标和源地址都非空,防止出现空指针异常assert(dst != NULL && src != NULL);while (count--) {// 将源地址对应的字节内容复制到目标地址对应的字节位置*(char*)dst = *(char*)src;// 目标和源地址分别向后移动一位,指向下一个字节位置dst = (char*)dst + 1;src = (char*)src + 1;}return ret;
}// 主函数
int main() {int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };int arr2[10] = { 0 };my_memcpy(arr2, arr1, 20);int i = 0;for (i = 0; i < 10; i++){printf("%d ", arr2[i]);}return 0;
}
思考1:为什么((char*)src)++
不行?
((char*)src)++
是错误的,因为它试图对一个临时值进行递增操作,导致未定义行为。src = (char*)src + 1;
是正确的,因为它先进行类型转换,再进行加法操作,最后将结果赋值给src
,符合C语言的语法规则和逻辑。
思考2 :memcpy
和strncpy
的区别?
- 操作对象 :
memcpy
操作的是内存块,按字节复制;strncpy
专门用于处理字符串,复制字符直到遇到字符串结束符'\0'
或复制完指定数量的字符。 - 终止条件 :
memcpy
不检查字符串结束符'\0'
,严格复制指定字节数;strncpy
会在遇到'\0'
时停止复制(除非要复制的字符数大于字符串长度)。 - 安全性 :
strncpy
在处理字符串时更安全,能避免因未正确处理结束符导致的缓冲区溢出等问题;memcpy
若使用不当,容易引发内存越界问题。
2、memmove使用和模拟实现
2.1 memmove的使用
介绍:
- 头文件:
string.h
- 函数原型:
void* memmove(void* destination, const void* source, size_t num);
- 作用:功能和
memcpy
一样,差别是memmove
能处理源空间和目标空间的重叠情况。 - 参考:https://legacy.cplusplus.com/reference/cstring/memmove/
2.2 memmove的模拟实现
讲解模拟实现之前,先讲讲while(num--)
,这个理解很重要。
#include <stdio.h>// 主函数
int main() {int num = 3;while (num--) {printf("num is now: %d\n", num);}return 0;
}
运行:
num is now: 2
num is now: 1
num is now: 0
总结:
- 当前值用于判断循环条件,然后才减 1。
然后讲解模拟实现:
#include <stdio.h>
#include <assert.h> void* my_memmove(void* dst, const void* src, size_t count) {assert(dst != NULL && src != NULL);void* ret = dst;if (dst < src){while (count--){*(char*)dst = *(char*)src;dst = (char*)dst + 1;src = (char*)src + 1;}}else{while (count--){*((char*)dst + count) = *((char*)src + count);}}return ret;
}// 主函数
int main() {int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };//my_memmove(arr1, arr1+2, 20); // d < smy_memmove(arr1 + 4, arr1 + 2, 20); // d < sint i = 0;for (i = 0; i < 10; i++){printf("%d ", arr1[i]);}printf("hello");return 0;
}
总结:在移动过程中,想象目标地址(dst)可以灵活调整位置。在不断比较中清晰掌握目标地址小于源地址(dst < src)和源地址大于目标地址(src > dst)的两种情况。
3、memset函数的使用
3.1 memset的使用
介绍:
- 头文件:
string.h
- 函数原型:
void* memset(void* ptr, int value, size_t num);
- 作用:将
ptr
指向的内存块的前num
个字节都设置为value
(以unsigned char
形式解释)。 - 参考:https://legacy.cplusplus.com/reference/cstring/memset/
3.2 memset的模拟实现
#include <stdio.h>void* my_memset(void* ptr, int value, size_t num) {unsigned char* p = (unsigned char*)ptr;while (num--) {*p++ = (unsigned char)value;}return ptr;
}// 主函数
int main() {char str[] = "almost every programmer should know memset!";my_memset(str, '-', 6);printf("%s\n", str);return 0;
}
运行:
------ every programmer should know memset!
4、memcmp函数的使用
4.1 memcmp的使用
介绍:
- 头文件:
string.h
- 函数原型:
int memcmp(const void* ptr1, const void* ptr2, size_t num);
- 作用:比较
ptr1
和ptr2
指向的内存块的前num
个字节。若相等返回0;若ptr1
所指内存大于ptr2
,返回正数;否则返回负数。 - 参考:https://legacy.cplusplus.com/reference/cstring/memcmp/
4.2 memcmp的模拟实现
#include <stdio.h>int my_memcmp(const void* ptr1, const void* ptr2, size_t num) {const unsigned char* p1 = (const unsigned char*)ptr1;const unsigned char* p2 = (const unsigned char*)ptr2;while (num--) {if (*p1 != *p2) {return *p1 - *p2;}p1++;p2++;}return 0;
}// 主函数
int main() {char buffer1[] = "DWgaOtP12df0";char buffer2[] = "DWGAOTP12DF0";int n = my_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'.
完。