在阅读本篇文章之前,建议读者优先阅读完成本专栏内前面的文章。
目录
前言
本篇文章主要来介绍与C语言内存函数相关的知识。
一、memcpy函数的使用和模拟实现
我们首先来看一下memcpy函数的函数声明:
cpp
void * memcpy ( void * destination, const void * source, size_t num );
这个函数实现的功能就是从source位置开始向后复制num个字节的数据到destination指向的内存位置,并且遇到\0的时候不会停下来。需要注意的是,如果source和destination发生了重叠,复制的结果就会是未定义的。我们可以键入如下的代码:
cpp
#include <stdio.h>
#include <string.h>
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[10] = { 0 };
memcpy(arr2, arr1, 20);
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr2[i]);
}
return 0;
}
其运行结果如下:

现在我们来模拟实现一下这个函数,基本的思路就是我们将source的每个字节都复制到destination直到num个字节,那么我们首先需要把这两个指针都强转成char*类型以完成字节级的操作,然后借用循环来完成代码。请读者先思考如何实现,我给出我的示例代码:
cpp
#include <stdio.h>
#include <string.h>
#include <assert.h>
//模拟实现memcpy函数
void* my_memcpy(void* dst, const void* src, size_t count)
{
void* ret = dst;
assert(dst);
assert(src);
/*
* copy from lower addresses to higher addresses
*/
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;
}
其运行结果如下:

二、memmove的使用和模拟实现
我们刚才在上面提及到了,memcpy函数是无法处理内存重叠的复制的,而我们如果想实现这个功能,就要去使用memmove函数了,我们首先先看一下它的函数声明:
cpp
void * memmove ( void * destination, const void * source, size_t num );
这个memmove函数就是可以处理源内存块和目标内存块重叠的复制。我们键入如下的代码:
cpp
#include <stdio.h>
#include <string.h>
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
memmove(arr1+2, arr1, 20);
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr1[i]);
}
return 0;
}
其运行结果如下:

下面我们来尝试自行实现一下这个函数。那么它的基本思路是什么呢?我们需要知道有些时候,比如说我们在上面举出的例子,我们需要优先拷贝靠后的元素;而另外一些时候,我们则需要优先拷贝靠前的元素。因此我们解决这个问题的关键就是判断出何时采用何种复制方法。那判断的方法其实也很简单,我们只需要了解哪个指针在左,哪个指针在右即可解决这个问题。接下来请读者先行自己思考,我给出我的示例代码:
cpp
#include <stdio.h>
#include <string.h>
#include <assert.h>
//模拟实现memmove函数
void* my_memmove(void* dst, const void* src, size_t count)
{
void* ret = dst;
if (dst <= src || (char*)dst >= ((char*)src + count)) {
/*
* Non-Overlapping Buffers
* copy from lower addresses to higher addresses
*/
while (count--) {
*(char*)dst = *(char*)src;
dst = (char*)dst + 1;
src = (char*)src + 1;
}
}
else {
/*
* Overlapping Buffers
* copy from higher addresses to lower addresses
*/
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 arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
my_memmove(arr1 + 2, arr1, 20);
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr1[i]);
}
return 0;
}
其结果如下:

三、memset函数的使用
memset函数是用来设置内存的,它可以将内存中的值以字节为单位设置成我们想要的内容,我们来看看它的函数声明:
cpp
void * memset ( void * ptr, int value, size_t num );
这个ptr指向了我们想要操作的内存块位置,value则交代了我们要设置的值,num则代表我们要设置多少个字节为value值。我们键入如下的代码:
cpp
#include <stdio.h>
#include <string.h>
int main ()
{
char str[] = "hello world";
memset (str,'x',6);
printf(str);
return 0;
}
其运行结果如下:

需要注意的是,这个函数是以字节为单位来设置的,也就是说如果我们这么使用的话:
cpp
int arr[5] = {0};
memset(arr, 1, 200);
那我们数组中的每个元素0都会出现从第一行到第二行的变化:
cpp
00 00 00 00
01 01 01 01
四、memcpy函数的使用
我们专门使用这个函数来比较两个内存,先看看它的函数声明:
cpp
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
它会比较从ptr1和ptr2指针指向的位置开始向后的num个字节,然后根据不同的结果给出如下不同的返回值:

我们键入如下的代码:
cpp
#include <stdio.h>
#include <string.h>
int main()
{
char buffer1[] = "DWgaOtP12df0";
char buffer2[] = "DWGAOTP12DF0";
int n;
n = 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;
}
其运行结果如下:

总结
本文介绍了C语言中常用的内存操作函数及其实现方法。重点讲解了memcpy函数的使用与模拟实现,分析了其无法处理内存重叠的局限性;详细说明了memmove函数如何处理重叠内存块的复制,并提供了模拟实现方案;简要介绍了memset函数的内存设置功能和memcmp函数的内存比较功能。通过代码示例演示了这些函数的具体应用场景和实现原理,为理解和掌握C语言内存操作提供了实用参考。