C语言内存函数
它是针对内存块来处理的,内存块就是一块内存
mem - 记忆、内存的意思
memcpy - 内存拷贝
memmove - 内存移动
memset - 内存设置
memcmp - 内存比较
这些函数使用时都需要包含对应的头文件 string.h
memcpy
该函数属于泛型函数,他可以拷贝整型数据、浮点型数据、结构体数据等等。因此它的类型是void *
。
表达式如下:
void * memcpy ( void * destination, const void * source, size_t num );
destination:目标空间的地址
source: 源空间的地址
num :被拷贝的字节个数
它返回的是目标空间的起始地址
memcpy函数从源头开始的位置复制num个字节的数据到目标空间所在内存的位置
需要注意的:
目标空间的内存足够大
memcpy遇到’\0’ 不会停止,该拷贝多少个字节就拷贝多少
memcpy只负责不重叠的拷贝,不负责重叠的拷贝,如果非要使用,它的结果是未定义的
memcpy的使用及模拟实现
思维逻辑图:
//memcpy的使用
#include<string.h>
int main()
{
int arr1[] = { 1,3,5,7,9,2,4,6,8,10 };
//arr1 + 3 :7的地址
int arr2[20] = { 0 };
//将arr1中的7,9,2,4,6拷贝到arr2中 4*5 = 20个字节
memcpy(arr2, arr1 + 3, 20);
int i = 0;
for (i = 0; i < 20; i++)
{
printf("%d ", arr2[i]);
}
return 0;
}
//模拟实现memcpy
#include<assert.h>
//不可修改加上const
void* my_memcpy(void* dest, const void* src, size_t num)
{
//(int*)dest = (int*)src;//如果强转为int*,权限不够细分,假设我想要17个字节呢
assert(dest && src);
void* ret = dest;//它的返回值是目标空间的起始地址,这里是为了防止后面dest++导致dest的起始地址发生改变
int i = 0;
for (i = 0; i < num; i++)
{
*(char*)dest = *(char*)src;//因为void* 不能够直接进行运算,需要强转
//dest++; //void* 不能够直接进行运算
//src++;
//(char*)dest++;
//(char*)src++;//因为强转是临时的,当我++后去使用它时他已经不是强转后的了
//++(char*)dest;//不能保证所有编译器都能够通过
//++(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
//while (num--)//也可以使用while来实现
//{
// *(char*)dest = *(char*)src;
// dest = (char*)dest + 1;
// src = (char*)src + 1;
//}
return ret;
}
int main()
{
int arr1[] = { 1,3,5,7,9,2,4,6,8,10 };
//arr1 + 3 :7的地址
int arr2[20] = { 0 };
//将arr1中的7,9,2,4,6拷贝到arr2中 4*5 = 20个字节
my_memcpy(arr2, arr1 + 3, 20);
int i = 0;
for (i = 0; i < 20; i++)
{
printf("%d ", arr2[i]);
}
return 0;
}
memmove
表达式如下:
void * memmove ( void * destination, const void * source, size_t num );
memmove函数来处理重叠的内存
memmove 的使用及模拟实现
思维逻辑图:
#include<string.h>
int main()
{
int arr1[] = { 1,3,5,7,9,2,4,6,8,10 };
//arr1 + 3 :7的地址
memmove(arr1 +2, arr1, 20);
return 0;
}
//memmove 模拟实现 --- 要将图画的过程自己思考并且画出来
#include<assert.h>
void* my_memmove(void* dest, void* src, size_t num)
{
assert(dest && src);
void* ret = dest;
if (dest < src)//从前往后
{
while (num--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
}
else//从后往前
{
while (num--)
{
*((char*)dest + num) = *((char*)src + num);//转换为char*的地址后加上减减后的num,以此达到从后向前的结果
}
}
}
int main()
{
int arr1[] = { 1,3,5,7,9,2,4,6,8,10 };
my_memmove(arr1 + 2, arr1, 20);//从前往后都可以试试
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr1[i]);
}
return 0;
}
C语言标准规定memcpy只要能实现不重叠的拷贝就行
重叠的交给memmove
在VS上可能能够实现,但不能够保证在其他编译器上能够正常运行
//memcpy 只负责重叠的就行,Vs是个特例
#include<string.h>
int main()
{
int arr1[] = { 1,3,5,7,9,2,4,6,8,10 };
memcpy(arr1 + 2, arr1, 20);//从前往后都可以试试
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr1[i]);
}
return 0;
}
memset 内存设置
memset函数 是用来设置内存的,将内存中的值以字节为单位设置成想要的内容
表达式如下:
void * memset ( void * ptr, int value, size_t num );
ptr: 你想要设置内存所指向的指针(地址)。
value:这里是你想要设置成怎样的值。
num:设置成值的字节数
memset的使用
#include<string.h>
int main()
{
char arr[] = "hello world";
memset(arr + 6, 'G', 5);//要记得加上 ''
printf("%s\n", arr);
return 0;
}
#include<string.h>
int main()
{
int arr[10] = { 0 };
memset(arr, 1, 4);//通过F10 + 内存 我们可以知道 memset 是以字节数为单位进行设置的,而不是以元素为单位进行设置的
return 0;
}
memcmp函数 - 内存比较
比较ptr1 和 ptr2 各自指向的地址开始向后num个字节的大小
表达式如下:
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
ptr1 和ptr2 :两个要进行比较的内存大小的地址
num: 比较它俩各自大小的字节数
memcmp函数不仅仅可以比较字符串类型的,其他类型的也可以进行比较
memcmp 的使用
#include<string.h>
int main()
{
char arr1[] = "i love you forever";
char arr2[] = "i love you noforever";
int ret1 = memcmp(arr1, arr2, 11);
printf("%d\n", ret1);//0
int ret2 = memcmp(arr1, arr2, 12);
printf("%d\n", ret2);//-1
return 0;
}
//整型类型的比较
#include<string.h>
int main()
{
//0000 0000 00000000 00000000 00000001
//0x00 00 00 01
int arr1[] = { 1,2,3,4,5 };
//01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00
int arr2[] = { 1,2,3,6,5 };
//01 00 00 00 02 00 00 00 03 00 00 00 06 00 00 00 05 00 00 00
//数据在内存中是以16进制倒着存放的
int ret = memcmp(arr1, arr2, 13);
printf("%d\n", ret);
return 0;
}
memcmp函数如果: 在VS上分别返回
ptr1 < ptr2 返回小于0的值 -1
ptr1 = ptr2 返回0 0
ptr1 > ptr2 返回大于0的值 1