《C语言》内存函数
本文介绍了四个内存操作函数的使用和实现方法:1. memcpy函数用于非重叠内存的复制,通过逐字节拷贝实现;2. memmove函数处理可能重叠的内存复制,根据源地址和目标地址的相对位置决定拷贝方向;3. memset函数以字节为单位设置内存值;4. memcmp函数比较两段内存内容。文章给出了各函数的原型说明、使用示例和模拟实现代码,重点分析了memmove处理内存重叠情况的策略,包括前向后拷贝
·
1 memcpy函数的使用和模拟实现
void* memcpy ( void* destination, const void* source, size_t num );
- 函数memcpy从source的位置开始向后复制num个字节的数据到destination指向的内存位置。
- 这个函数在遇到 '\0' 的时候并不会停下来。
- 如果source和destination有任何重叠,复制的结果都是未定义的,对于重叠的内存,交给memmove函数来处理。
- memcpy函数可以复制任何类型的数据。
- memcpy函数的使用需要包含 string.h 头文件。
#include<stdio.h>
#include<string.h>
int main()
{
int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[10] = { 0 };
int arr3[10] = { 0 };
//将arr1中的1 2 3 4 5拷贝到arr2中
memcpy(arr2, arr1, 5 * sizeof(int));
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr2[i]);
}
printf("\n");
//将arr1中的4 5 6 7 8拷贝到arr3中
memcpy(arr3, arr1 + 3, 5 * sizeof(int));
for (i = 0; i < 10; i++)
{
printf("%d ", arr3[i]);
}
return 0;
}
输出结果为:

memcpy模拟实现:
#include<assert.h>
void* my_memcpy(void* dest, const void* src, size_t num)
{
void* ret = dest;
assert(dest && src);
while (num--)
{
*(char*)dest = *(char*)src; //强制类型转换是临时的效果
//((char*)dest)++;
//((char*)src)++;
//上面注释中的写法有的编译器编译不了,我们就采用下面的写法
dest = (char*)dest + 1;
src = (char*)src + 1;
}
return ret;
}
2 memmove函数的使用和模拟实现
void* memmove ( void* destination, const void* source, size_t num );
- 和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
- 如果源空间和目标空间出现重叠,就得使用memmove函数处理。
#include<stdio.h>
#include<string.h>
int main()
{
int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
memmove(arr1, arr1+3, 5 * sizeof(int));
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr1[i]);
}
printf("\n");
int arr2[10] = { 1,2,3,4,5,6,7,8,9,10 };
memmove(arr2 + 3, arr2, 5 * sizeof(int));
for (i = 0; i < 10; i++)
{
printf("%d ", arr2[i]);
}
return 0;
}
输出结果为:

memmove模拟实现:
memmove拷贝的时候,会出现三种情况:
- 源空间和目标空间重叠,目标空间包含源空间尾部的一部分
- 源空间和目标空间重叠,目标空间包含源空间头部的一部分
- 源空间和目标空间未重叠
源空间和目标空间重叠,目标空间包含源空间尾部的一部分
这种情况如果是dest从前往后拷贝的话,就会覆盖掉src中尾部的数据,为了避免数据覆盖,我们可以采用dest从后往前拷贝,这样就不会覆盖掉src的数据,实现目标拷贝。
源空间和目标空间重叠,目标空间包含源空间头部的一部分
这种情况如果还是像上一种情况那样采用dest从后往前拷贝的话,就会覆盖掉src中头部的数据,为了避免覆盖,我们就正常采用dest从前往后拷贝,这样就不会覆盖掉src的数据,实现目标拷贝。
源空间和目标空间未重叠
这种情况就跟前面memcpy函数的拷贝一样了,没发生数据重叠,数据不会被覆盖,想dest从前往后拷贝还是dest从后往前拷贝都不影响最终的结果。
这里我们采用:dest指向src前面的空间就让dest从前往后拷贝,dest指向src后面的空间就让dest从后往前拷贝。

#include<assert.h>
void* my_memmove(void* dest, const void* src, size_t num)
{
void* ret = dest;
assert(dest && src);
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);
}
}
return ret;
}
3 memset函数的使用
void* memset ( void* ptr, int value, size_t num );
- memset是用来设置内存的,将内存中的值以字节为单位设置成想要的内容。
#include<stdio.h>
#include<string.h>
int main()
{
char arr[] = "hello PIKU";
memset(arr, 'O', 6);
printf("%s\n", arr);
return 0;
}
输出结果为:

4 memcmp函数的使用
int memcmp ( const void* ptr1, const void* ptr2, size_t num );
- 比较从ptr1和ptr2指针指向的位置开始,向后的num个字节
- 可以比较任意类型的数据
- 标准规定:
①第一个指针指向的数据大于第二个指针指向的数据,则返回大于0的数字
②第一个指针指向的数据等于第二指针指向的数据,则返回0
③第一个指针指向的数据小于第二个指针指向的数据,则返回小于0的数字

#include<stdio.h>
#include<string.h>
int main()
{
int arr1[] = { 1 ,2,3,4,5,6,7,8,9,10 };
int arr2[] = { 1,2,3,4,8 };
int ret = memcmp(arr1, arr2, 16);
printf("%d\n", ret);
return 0;
}
输出结果为:

#include<stdio.h>
#include<string.h>
int main()
{
int arr1[] = { 1 ,2,3,4,5,6,7,8,9,10 };
int arr2[] = { 1,2,3,4,8 };
int ret = memcmp(arr1, arr2, 17);
printf("%d\n", ret);
return 0;
}
输出结果为:


更多推荐





所有评论(0)