精通C语言(1.内存函数)
本文介绍了C语言中四个常用的内存操作函数:memcpy、memmove、memset和memcmp的使用方法与实现原理。memcpy用于内存拷贝,但存在重叠区域问题;memmove是memcpy的升级版,能处理重叠拷贝;memset用于内存填充;memcmp用于内存比较。文章通过代码示例详细演示了各函数的用法,并提供了memcpy和memmove的模拟实现,帮助读者深入理解这些底层函数的运作机制。
- 🌈🌈🌈这里是say-fall分享,感兴趣欢迎三连与评论区留言
- 🔥🔥🔥专栏:《C语言入门知识点》、《C语言底层》
- 💪💪💪格言:今天多敲一行代码,明天少吃一份苦头
前言:
随着指针篇的完结,C语言大部分知识点其实已经全部被学完,下面我们来看一下几个C语言内置的一些内存函数,包括memcpy、memmove、memset和memcmp,如果各位观众有兴趣的话,不妨跟着我来了解一下他们的用法,快记好笔记~
文章目录
正文:
1. memcpy的使用和模拟实现
1.1 memcpy的使用
首先我们来了解一下memcpy的标准形式与参数
它的作用是将一些值拷贝在另一处
void * memcpy ( void * destination, const void * source, size_t num );
void*
为返回类型
void* destination
为“复制目标地点”
const void* source
为“复制源”
size_t num
为“复制值的字节数”
接着我们来看一下
memcpy
究竟是什么效果
#include <stdio.h>
#include <string.h>
#include <assert.h>
int main()
{
int arr1[10] = { 0,1,2,3,4,5,6,7,8,9 };
int arr2[20] = { 0 };
int i = 0;
for (i = 0; i < sizeof(arr2) / sizeof(arr2[0]); i++)
{
printf("%d ", arr2[i]);
}
printf("\n");
memcpy(arr2, arr1 + 1, 20);
for (i = 0; i < sizeof(arr2) / sizeof(arr2[0]); i++)
{
printf("%d ", arr2[i]);
}
return 0;
}
运行结果:
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 2 3 4 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1.2 memcpy的模拟实现
首先参数的确定是和原函数一样的,这样的话确定了参数,然后我们来思考一下怎么去”copy“
还记得我们之前qsort函数是怎么交换的吗?
以下展示:
同理,我们这里也用这个方法,因为不管是什么类型,都能以单个字节来赋值或者说拷贝:
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
解决了这个大问题以后,我们只需要确定返回的是“目标地址”就好了,下面是完整代码和使用:
#include <stdio.h>
#include <string.h>
#include <assert.h>
void* my_memcpy(void* dest, const void* src, size_t num);
int main()
{
int arr1[10] = { 0,1,2,3,4,5,6,7,8,9 };
int arr2[20] = { 0 };
int i = 0;
for (i = 0; i < sizeof(arr2) / sizeof(arr2[0]); i++)
{
printf("%d ", arr2[i]);
}
printf("\n");
my_memcpy(arr2, arr1 + 1, 20);
for (i = 0; i < sizeof(arr2) / sizeof(arr2[0]); i++)
{
printf("%d ", arr2[i]);
}
return 0;
}
void* my_memcpy(void* dest, const void* src, size_t num)
{
const void* ret = dest;
assert(dest && src);
while (num--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
return ret;
}
运行结果完全一致:
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 2 3 4 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2. memmove的使用和模拟实现
memmove
是干什么的,和memcpy
有什么区别?
在讨论这个问题之前,我们先再用memcpy
来拷贝一下:
#include <stdio.h>
#include <string.h>
#include <assert.h>
void* my_memcpy(void* dest, const void* src, size_t num);
int main()
{
int arr1[10] = {0,1,2,3,4,5,6,7,8,9};
int arr2[20] = { 0 };
int i = 0;
for (i = 0; i < sizeof(arr1) / sizeof(arr1[0]); i++)
{
printf("%d ", arr1[i]);
}
printf("\n");
my_memcpy(arr1 + 3, arr1, 20);
for (i = 0; i < sizeof(arr1) / sizeof(arr1[0]); i++)
{
printf("%d ", arr1[i]);
}
return 0;
}
void* my_memcpy(void* dest, const void* src, size_t num)
{
const void* ret = dest;
assert(dest && src);
while (num--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
return ret;
}
运行结果:
0 1 2 3 4 5 6 7 8 9
0 1 2 0 1 2 0 1 8 9
我们发现他并没有完全的拷贝到位,而是出现了重复,如果仔细分析的话就会发现是因为之前拷贝的影响到了后面的值(因为有交集)
这样的话我们不妨从后面开始赋值:
while (num--)
{
*((char*)dest + num)= *((char*)src + num);
}
这样的话好像出现了另一种情况,便出现了分类:
这样处理一下:
void* my_memmove(void* dest, const void* src, size_t num)
{
const 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;
}
如果注意细节的话就能发现这个函数其实就是
my_memmove
函数
接下来讲解一下什么是memmove
,这个函数其实可以理解为一个memcpy
的 “升级版 ”
因为他完全可以杜绝掉拷贝有交集重叠的问题
所以,他们两个几乎完全一致:
void * memmove ( void * destination, const void * source, size_t num );
void*
为返回类型
void* destination
为“复制目标地点”
const void* source
为“复制源”
size_t num
为“复制值的字节数”
3. memset的使用
memset有点像是直接给内存赋值的一个函数
void * memset ( void * ptr, int value, size_t num );
这里直接展示一个实例:
#include <stdio.h>
#include <string.h>
int main()
{
char str[] = "hello world";
memset(str+5, 'x', 6);
printf(str);
return 0;
}
运行结果:
helloxxxxxx
通过实例我们可以发现这个函数就是把
ptr
这个地址以后的值赋成value
,一共赋num
个字节
4. memcmp的使用
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
ptr1
和ptr2
两个是要比较的地址,num
是比较的字节数
如果前者大就返回正值,反之为负,相等为正
这里直接拿来主义一个例子:
#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;
}
运行结果:
'DWgaOtP12df0' is greater than 'DWGAOTP12DF0'.
证明了
buffer1[]
更大一些,原因是g的ASCII码比G的大32
- 本节完…
更多推荐
所有评论(0)