---------------------------------------------
夜色难免黑凉,前行必有曙光。
-------------今天我将带大家认识C语言中的内存函数
---------的使用和模拟实现
-----这些函数的头文件依然被#include<string.h>所包含
目录
memcpy函数的使用
memcpy函数的模拟实现
memmove函数的使用
memmove函数的模拟实现
memset函数的使用
memcmp函数的使用
memcpy函数的使用
void * memcpy ( void * destination, const void * source, size_t num );
1.函数memcpy是从cource的位置开始向后复制num的字节数据到destination指向的内存位置
2.函数memcpy在遇到'\0'并不会停下来,依然可以拷贝'\0'后面位置
3. source和destination不能有重叠
4.常被我们用来拷贝非字符串的类型
以下是memcpy函数的一般用法:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
int main()
{
int arr[] = { 1,3,5,7,9,2,4,6,8,0 };
int str[10] = { 0 };
memcpy(str,arr , 20);
//内存函数的单位是字节,20字节就是5个整形元素
//也可以这么写memcpy(str,arr,5*sizeof(int))
for (int i = 0; i < 5; i++)
{
printf("%d ", str[i]);
}
return 0;
}
我们来验证一下,memcpy遇到'\0'是否不会停止:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
int main()
{
char arr[] = "Hel\0lo World!";
char str[10] = { 0 };
memcpy(str, arr, 6 * sizeof(char));
for (int i = 0; i < 6; i++)
{
printf("%c", str[i]);
}
return 0;
}
我们可以看到memcpy函数并不会因为遇到'\0'而停止,它会把'\0' 拷贝到目标函数
memcpy函数的模拟实现
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
void* my_memcpy(void* arr, const void* str, size_t num)
//因为这个函数可以运用到多种类型,所以用了void*(无具体类型的指针)
{
void* ret = arr;
while (num--)
{
*(char*)arr = *(char*)str;
arr = (char*)arr+1;
str = (char*)str + 1;
//强制类型转换为char类型可以一个字节一个字节的访问
}
return ret;
//返回目标函数的起始地址
}
int main()
{
char arr[] = { 1,3,5,7,9,2,4,6,8,0 };
char str[10] = { 0 };
my_memcpy(str, arr, 5 * sizeof(int));
for (int i = 0; i < 5; i++)
{
printf("%d ", str[i]);
}
return 0;
}
memcpy中重叠拷贝问题:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
void* my_memcpy(void* arr, const void* str, size_t num)
{
void* ret = arr;
while (num--)
{
*(char*)arr = *(char*)str;
arr = (char*)arr + 1;
str = (char*)str + 1;
}
return ret;
}
int main()
{
int arr[10] = { 1,3,5,7,9,2,4,6,8,0 };
my_memcpy(arr+3, arr, 5 * sizeof(int));
for (int i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
VS2022的库函数里面的memcpy可以重叠拷贝,但有些编译器不行
为了表示区分,我们以后重叠拷贝都不用memcpy
可以用memmove函数来实现重叠拷贝
memmove函数的使用
void * memmove ( void * destination, const void * source, size_t num );
1.memmove和memcpy的区别就是源内空间可以和目标空间重叠
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
int main()
{
int arr[10] = { 1,3,5,7,9,2,4,6,8,0 };
memmove(arr+3, arr, 5 * sizeof(int));
for (int i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
我们可以发现memmove把我们刚刚源内空间和目标空间重叠的问题很好的解决了
接下来让我们看看它是怎么实现的吧
memmove函数的模拟实现
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
void* my_memmove(void* dst, const void* src, size_t count)
{
void* ret = dst;
if (dst <= src || (char*)dst >= ((char*)src + count)) {
while (count--) {
//从前向后拷贝
*(char*)dst = *(char*)src;
dst = (char*)dst + 1;
src = (char*)src + 1;
}
}
else {
//从后向前拷贝
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()
{
int arr[10] = { 1,3,5,7,9,2,4,6,8,0 };
my_memmove(arr + 3, arr, 5 * sizeof(int));
for (int i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
接下来我将会以画图的形式帮助大家理解:
memset函数的使用
void * memset ( void * ptr, int value, size_t num );
1.memsrt常被我们用来设置内存,将内存中的值以字节为单位设置成想要的内容
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
int main()
{
char arr[] = "hello world";
memset(arr, 'x', 6);
printf(arr);
return 0;
}
这样来看我们是不是把hello 的内容设置成"x"了!这就是memset函数的运用场景。
memcmp函数的使用
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
1.比较ptr1和ptr2指针指向的位置开始,向后的num个字节
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
int main()
{
char arr[] = "abcdfe";
char str[] = "abcdefg";
int n;
n = memcmp(arr, str, sizeof(arr));
if (n > 0)
printf("'%s' 大于 '%s'.\n",arr ,str );
else if (n < 0)
printf("'%s' 小于 '%s'.\n", arr,str );
else
printf("'%s' 等于 '%s'.\n",arr ,str );
return 0;
}
今天的介绍就到这里啦!
后续我将会把结构体方面的知识点整理出来
希望大家长期关注 !
感谢支持