C语言内存操作函数
Posted 蓝乐
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C语言内存操作函数相关的知识,希望对你有一定的参考价值。
简述
本文将介绍几个关于内存操作常见的库函数,即memcpy,memmove,memcmp以及memset函数。
memcpy–内存拷贝函数
void * memcpy ( void * destination, const void * source, size_t num );
memcpy函数和之前所介绍的strcpy函数类似,只是这次拷贝的内容不是字符串,而是各种类型的内存,因此对于memcpy的num参数代表的内存的字节数,即:
1.函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
2.这个函数在遇到 ‘\\0’ 的时候并不会停下来。
那么对于memcpy函数的实现就变得很简单了,思路与strcpy一样,只不过要将两个指针强制类型转换为char* 型,代码如下:
void* my_memcpy(void* dest, void* src, size_t num)
{
assert(dest && src);//防止对NULL解引用
void* ret = dest;//返回dest指针最初所指的地址
while (num--)//将src中num个字节的内存拷贝到dest中
{
*((char*)dest) = *((char*)src);
dest = (char*)dest + 1;
src = (char*)src + 1;
}
return ret;
}
用整形数组来看看代码的效果如何:
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9 };
int arr2[10] = { 0 };
my_memcpy(arr2, arr1, 20);//将arr1中20个字节即5个元素拷贝到arr2中
int i = 0;
for (i = 0; i < 5; i++)//将arr2中前5个元素打印
printf("%d ", arr2[i]);
return 0;
}
可以看出代码的实现是符合预期的,那么现在有一个问题,memcpy是否可以将同一个数组的内容进行拷贝,即对于source和destination有重叠的情况下:
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9 };
my_memcpy(arr1 + 2, arr1, 20);//将arr1中20个字节即5个元素拷贝到arr1第三个元素开始的位置处
int i = 0;
for (i = 0; i < 9; i++)//将arr1数组打印
printf("%d ", arr1[i]);
return 0;
}
我们预期打印的内容是:121234589,但是运行后的结果如下:
这显然不符合我们的预期,那么原因是什么呢?我们根据代码的逻辑来画个图理解一下:
每次拷贝后的数据将覆盖掉原有数据,因此经过5个元素的拷贝后,数组arr1变成了:1 2 1 2 1 2 1 8 9.
但是当我们直接调用编译器库函数<memory.h>中的函数时,会发现结果时符合我们的预期的:
这并不是说我们所实现的memcpy函数不对,根据C语言标准,memcpy只需要实现没有重叠部分的内存拷贝即可,而编译器中的memcpy函数实际上是加强了功能那么这个功能是怎么实现的呢?下面我们将来介绍memmove函数。
memmove–处理内存有重叠部分的拷贝函数
void * memmove ( void * destination, const void * source, size_t num );
可以发现memmove函数的参数与memcpy的一样,其实二者的意义也是完全一样的,只不过memmove函数可以实现内存有重叠的情况,即:
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
memmove(arr + 2, arr, 20);//将arr数组中前5个元素拷贝到3到7个元素的位置上
int i = 0;
for (i = 0; i < 10; i++)//将arr数组打印
printf("%d ", arr[i]);
return 0;
}
那么这个函数要怎么实现呢?需要分集中情况讨论:
因此只需要在memcpy的基础上在添加一种从后往前的情况即可,代码实现:
void* my_memmove(void* dest, void* src, size_t num)
{
assert(dest && src);//防止对NULL解引用
void* ret = dest;//记录最初的dest所指的地址
if (dest < src)
{
while (num--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
}
else
{
dest = (char*)dest + num - 1;
src = (char*)src + num - 1;
while (num--)
{
//*((char*)dest + num) = *((char*)src + num);
*(char*)dest = *(char*)src;
dest = (char*)dest - 1;
src = (char*)src - 1;
}
}
return ret;
}
介绍完memcpy和memmove两个函数后,接下来再介绍一下memcmp函数。
memcmp–内存比较函数
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
memcmp函数与strncmp函数类似,只不过memcmp函数可以比较任何类型的内容。用memcmp函数来比较,需要传入待比较的内存大小,单位是bit。
下面是memcmp比较两个字符串的例子:
int main()
{
char str1[] = "never give up";
char str2[] = "never get lost";
int ret = memcmp(str1, str2, sizeof(str1));
printf("%d\\n", ret);
return 0;
}
memset–内存设置函数
void * memset ( void * ptr, int value, size_t num );
memset函数的各个参数含义:ptr–指针指向的待设置的内存块。
value–是待设置的变量,即填充到ptr所指的内存块中的变量,其类型是int。
num:所要设置的value的个数。
memset函数的作用是将num个value变量填充到ptr所指的内存块中。比如:
int main()
{
char str[] = "never give up";
memset(str, '0', 6);
printf("%s\\n", str);
return 0;
}
那么memset的实现也很简单了:
void* my_memset(void* ptr, int value, size_t num)
{
assert(ptr != NULL);
void* ret = ptr;//记录ptr最初所指的位置
while (num--)//依次填充value到ptr所指的内存块中
{
*(char*)ptr = value;
ptr = (char*)ptr + 1;
}
return ret;
}
以上是关于C语言内存操作函数的主要内容,如果未能解决你的问题,请参考以下文章
C 语言文件操作 ( fflush 函数 | 刷新缓冲区示例代码 )