前言:
C语言中除了字符串函数和字符函数外,还有一些函数可以直接对内存进行操作,这些函数被称为内存函数,这些函数与字符串函数都属于<string.h>这个头文件中。
一.memcpy()函数
memcpy是C语言中的一个内存函数,用来将source地址的num个字节复制到destination处。该函数可以处理任何数据,所以参数和返回值的类型都是void*。需要注意的是,该函数遇到\0之后不会停止,直到复制完num个字节。该函数要求目标地址的内存空间必须足够大,要能够容纳复制的内容。
虽然memcpy函数是有返回值的,但是我们可以选择不接受,这是没问题的。
如果源地址处没有num个字节,memcpy也不会停止,会顺着源地址向后寻找字节,直到复制完num个字节:
如上图所示,源地址只有16个字节,而memcpy函数却要复制20个字节的内容,这时候复制完16个字节之后会从该处继续向后复制四个字节,所以打印出来是随机值。
注意:memcpy处理重叠内存的复制,结果是未定义的。意思就是如果源地址与目标地址由重叠区域,就别用memcpy函数,虽然memcpy可以实现,但是有memmove函数专门来实现重复区域的复制。
1.memcpy的模拟实现
因为memcpy函数可以针对内存进行操作,那就说明它可以对任何数据进行复制,所以我们将参数设置成void*类型,以便接受各种类型的数据。
既然可以接受各种数据,那么怎么实现数据的复制呢?
我们可以将所有数据类型都转换成char*类型,我们只需要一个字节一个字节的复制就行了,因为我们知道一共要复制多少个字节,所以借助循环语句,将每个字节一一复制就行。
//memcpy函数的模拟实现
#include <stdio.h>
#include <string.h>
#include <assert.h>
void* my_memcpy(void* destination, const void* source, size_t num)
{
assert(destination && source);
void* ret = destination;
while (num--)
{
*(char*)destination = *(char*)source;
destination = (char*)destination + 1;
source = (char*)source + 1;
}
return ret;
}
int main()
{
int nums1[] = { 1,2,3,4,5 };
int nums2[20] = { 0 };
my_memcpy(nums2, nums1, sizeof(int) * 5);
int i = 0;
for (i = 0; i < 20; i++)
{
printf("%d ", nums2[i]);
}
return 0;
}
二.memmove()函数
该函数与memcpy的区别就在于,该函数可以处理重叠部分的内存复制。在处理两个毫不相关的内存复制的时候,功能与memcpy函数一摸一样。
在该函数中,arr是目标地址,arr+2是源地址,而要交换的是三个字节,这两个地址有重叠的部分,遇到要复制这种情况的就可以使用memmove函数。
1.memmove函数的模拟实现
该函数与memcpy的区别在于可以复制内存重叠部分,所以它可以算得上是memcpy的升级,既可以完成memcpy的功能,也可以完成它不可以完成的。
由图示可知,我们可以将重叠部分的复制分为两部分,源地址首地址小于目标地址,从后->前复制,反之由前->后。
//memmove函数的模拟实现
#include <stdio.h>
#include <assert.h>
void* my_memmove(void* destination, const void* source, size_t num)
{
assert(destination && source);
void* ret = destination;
//前->后
if (destination < source)
{
while (num--)
{
*(char*)destination = *(char*)source;
destination = (char*)destination + 1;
source = (char*)source + 1;
}
}
//后->前
else
{
while (num--)
{
*((char*)destination + num) = *((char*)source + num);
}
}
return ret;
}
int main()
{
//char str[] = "abcdef";
int arr[] = { 1,2,3,4,5 };
//char *ret1 = (char*)my_memmove(str+1, str, sizeof(char) * 3);
char *ret2 = (char*)my_memmove(arr+1, arr, sizeof(int) * 3);
//printf("%s\n", ret1-1);
int i = 0;
for (i = 0; i < 5; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
三.memset()函数
该函数的功能是将ptr地址中的num个字节修改设置成value值。
对于字符数组来说,一个字符占一个字节,故将5个字节修改成’1‘,就相当于将数组前五个元素设置成1。
四.memcmp()函数
memcmp的作用是比较ptr1和ptr2指向地址的num个字节的大小。
如果ptr1>ptr2,返回大于0的数;
ptr1 = ptr2,返回0;
ptr1<ptr2,返回小于0的数。
返回-1说明arr2第一个字节大于arr1的第一个字节。
图一左上角的是arr1的第一个字节,图二左上角是arr2的第一个字节,很显然4>1,所以函数返回-1。
完!