当前位置:网站首页>C语言之内存函数
C语言之内存函数
2022-08-09 05:04:00 【从未止步..】
在此之间,我们学过许多的字符函数,例如strcpy,strstr,strcmp等等,这里我们以strcpy函数进行举例:
//实现将arr1拷贝到arr2中
int main()
{
int arr1[5] = {
1,2,3,4,5 };
int arr2[5] = {
0 };
strcpy(arr2, arr1);
return 0;
}
程序并没有正确运行,编译器报错:
错误分析如下:上述代码是无法实现将arr1拷贝到arr2中,由此可见,像strcmp,strcpy,strstr这种字符串函数,它虽然能够实现字符串拷贝,比较等功能,但是由于它们的操作对象是字符串,因此对于整形数组,浮点型数组等并不适用。
那么对于整形数组,浮点型数组等其他的数据,我们该如何进行操作呢?
c语言给出了另一类函数-------内存函数(memcpy/memmove/memcmp)
memcpy:
//void*-----通用类型指针:可以接受各种类型的参数
void*memcpy(void*destination,const void*source,size_num)//size_num的单位是字节
还是选用上述实例:
#include<stdio.h>
#include<string.h>
//实现将arr1拷贝到arr2中
int main()
{
int arr1[5] = {
1,2,3,4,5 };
int arr2[5] = {
0 };
memcpy(arr2, arr1,sizeof(arr1));
return 0;
}
此时打开监视窗口,我们不难发现,数组之间完美的实现了拷贝。
结构体类型实现拷贝:
举例:
struct person
{
int age;
char name[20];
char phone[13];
};
int main()
{
struct person arr3[] = {
{
20,"张三","20031319"},{
19,"lisa","193684"} };
struct person arr4[3] = {
0};
memcpy(arr4, arr3, sizeof(arr3));
}
此时打开监视窗口,我们不难发现,结构体之间完美的实现了拷贝。
模拟实现memcpy:
以整形进行举例:
#include<stdio.h>
#include<assert.h>
void* my_memcpy(void* dest, const void* scr,size_t num)
{
void* ret = dest;
//断言:为避免是空指针
assert(dest != NULL);
assert(scr != NULL);
while (num--)//num为要拷贝的长度
{
//不能直接解引用操作的原因:void*类型不能直接进行++/--操作
*(char*)dest = *(char*)scr;//先强制类型转换在解引用
dest=(char*)dest+1;
scr=(char*)scr+1;
}
return ret;//不能直接返回dest,因为此时的dest并不是首地址
}
int main()
{
int arr1[] = {
1,2,3,4,5 };
int arr2[5] = {
0 };
my_memcpy(arr2, arr1,sizeof(arr1));
for (int i = 0; i < 5; i++)
{
printf("%d ", arr2[i]);
}
return 0;
}
1 2 3 4 5
上述实例,我们是实现的功能是将一个数组中的元素拷贝到另一个数组中,如果现在我们实现将数组中的前几个元素拷贝到后面的几个呢?
举例:
//实现将1 2 3 4 5拷贝到3 4 5 6 7的位置上
#include<stdio.h>
#include<assert.h>
void* my_memcpy(void* dest, const void* scr,size_t num)
{
void* ret = dest;
assert(dest != NULL);
assert(scr != NULL);
while (num--)
{
*(char*)dest = *(char*)scr;
dest=(char*)dest+1;
scr=(char*)scr+1;
}
return ret;
}
int main()
{
int arr1[] = {
1,2,3,4,5,6,7,8,9,10 };
my_memcpy(arr1+2, arr1,20);
for (int i = 0; i < 10; i++)
{
printf("%d ", arr1[i]);
}
return 0;
}
预期输出结果为:
1 2 1 2 3 4 5 8 9 10
实际输出结果:
1 2 1 2 1 2 1 8 9 10
预期和实际不相符分析如下:
由此可得出:我们所编写的my_memcpy函数并不能实现在同一个数组中的拷贝,会出现数的覆盖现象。
那库函数memcpy能否实现呢?
#include<stdio.h>
int main()
{
int arr1[] = {
1,2,3,4,5,6,7,8,9,10 };
memcpy(arr1+2, arr1,20);
for (int i = 0; i < 10; i++)
{
printf("%d ", arr1[i]);
}
return 0;
}
输出结果如下:
1 2 1 2 3 4 5 8 9 10
看到这里,相信很多人都会产生疑惑,为什么库函数memcpy可以实现,而我们编写的my_memcpy不能实现呢?难道是我们写错了?
事实并非如此,memcpy虽然也实现了这样的功能,但C语言标准规定:memcpy:用来处理不重叠的内存拷贝。memmove:处理重叠的内存拷贝
我们所编写的my_memcpy是因为严格按照C语言的标准所编写,而在VS编译器上memcpy超额完成了任务,相当于抢了memmove的饭碗。
下面我们就来学习memmove函数!
memmove:
依然是上述实例:
#include<stdio.h>
int main()
{
int arr1[] = {
1,2,3,4,5,6,7,8,9,10 };
memmove(arr1+2, arr1,20);
for (int i = 0; i < 10; i++)
{
printf("%d ", arr1[i]);
}
return 0;
}
输出结果如下:
1 2 1 2 3 4 5 8 9 10
现在得出的结果正是我们预期的效果!
模拟实现memmove:
目的地的地址低于源头地址:
正序进行拷贝:
#include<stdio.h>
#include<assert.h>
my_memmove(void* dest, const void* scr, size_t count)
{
assert(dest != NULL);
assert(scr != NULL);
void* ret = dest;
while (count--)
//直接按照源头一个个进行打印,不存在数的覆盖
{
*(char*) dest= *(char*) scr;
dest = (char*)dest + 1;
scr = (char*)scr + 1;
}
return ret;
}
int main()
{
int arr1[] = {
1,2,3,4,5,6,7,8,9,10 };
my_memmove(arr1, arr1+2,20);
for (int i = 0; i < 10; i++)
{
printf("%d ", arr1[i]);
}
return 0;
}
这种比较简单,这里就不赘述分析过程了输出结果为:
3 4 5 6 7 6 7 8 9 10
目的地址高于源头地址:
倒序进行拷贝:
#include<stdio.h>
#include<assert.h>
my_memmove(void* dest, const void* scr, size_t count)
{
assert(dest != NULL);
assert(scr != NULL);
void* ret = dest;
while (count--)
{
*((char*)dest + count) = *((char*)scr + count);
}
return ret;
}
int main()
{
int arr1[] = {
1,2,3,4,5,6,7,8,9,10 };
my_memmove(arr1+2, arr1,20);
for (int i = 0; i < 10; i++)
{
printf("%d ", arr1[i]);
}
return 0;
}
输出结果为:
1 2 1 2 3 4 5 8 9 10
对于该行代码的实现过程,我们分析如下:
*((char*)dest + count) = *((char*)scr + count);
对于上述两种情况,我们可用一个程序进行表示:
#include<stdio.h>
#include<assert.h>
my_memmove(void* dest, const void* scr, size_t count)
{
assert(dest != NULL);
assert(scr != NULL);
void* ret = dest;
if(dest<scr)//正序进行拷贝
while (count--)
{
*(char*)dest = *(char*)scr;
dest = (char*)dest + 1;
scr = (char*)scr + 1;
}
else//倒序进行拷贝
{
while(count--)
{
*((char*)dest + count) = *((char*)scr + count);
}
}
return ret;
}
int main()
{
int arr1[] = {
1,2,3,4,5,6,7,8,9,10 };
my_memmove(arr1+2, arr1,20);
for (int i = 0; i < 10; i++)
{
printf("%d ", arr1[i]);
}
return 0;
}
输出结果如下:
1 2 1 2 3 4 5 8 9 10
memcmp:
将两个存储区的前n个字节进行比较。
举例:
#include<stdio.h>
int main()
{
int arr[] = {
1,2,3,4,5 };
int arr2[] = {
1,2,5,4,3 };
int ret=memcmp(arr, arr2, 9);//arr>arr2,返回大于零的数字,arr<arr2,返回小于零的数字,二者相等,返回0
//注:VS编译器返回-1/0/1,虽然不严谨,但是并不违背C语言的标准规定
printf("%d\n", ret);
return 0;
}
输出结果如下:
-1
分析如下:
memset:内存设置函数
举例:
字符型:
#include<stdio.h>
int main()
{
char arr[10] = "";
memset(arr, '#', 10);//10代表更改10个字节
return 0;
}
整形:
#include<stdio.h>
int main()
{
int arr[10] = {
0};
memset(arr, 1, 10);
return 0;
}
输出如下:让不少人产生疑惑的是:为什么此时并没有实现将数组中的10个元素都修改为1呢?
原因是:该函数的操作单位是字节,而数组是一个整形数组,其中的元素都为整形,每个元素为4个字节。
具体分析如下:因此,在使用该函数的时候,一定要注意类型。
边栏推荐
猜你喜欢
随机推荐
ddr系统检验
How to choose an APS system, it is necessary to clarify these seven key factors
【Harmony OS】【ARK UI】Custom popup
【LeetCode】287. 寻找重复数
HP路由器和交换机日志分析
Perl basic grammar
数字化时代,企业为什么需要商业智能BI
【ITRA】2022年ITRA赛事注册流程 从0-1
如何选型APS系统,还需明确这七大关键因素
matlab simulink球杆控制系统的模糊PID控制设计
后台登录模块以及验证码登录
leetcode:402. 移掉 K 位数字
亚马逊面对风控,自养号测评时应该怎么做?
软件测试的发展趋势
【luogu U142356】勇者的后缀(SA)(主席树)(二分)
【HMS core】【Ads Kit】华为广告——海外应用在国内测试正式广告无法展示
区别如下概念:路径、绝对路径、相对路径、当前目录。系统磁盘上存在某个可执行文件,但在DOS环境输入其文件名却提示没有这个文件,是什么原因?
什么是通用微处理器、单片机、DSP芯片、嵌入式系统?
存储系统架构演变
力扣349-两个数组的交集——HashSet