当前位置:网站首页>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个字节。
具体分析如下:
因此,在使用该函数的时候,一定要注意类型。
边栏推荐
猜你喜欢

通讯录(文件版)(C语言)(VS)

Harmony OS ets ArkUI 】 【 】 development create a view and building layout

Zuul---路由功能

LN论文、五种归一化原理和实现

The development trend of software testing

JS-全局dom对象的使用---使用htm样式和js函数动作的完全分离

equals and ==

2022下半年深圳信息系统项目管理师认证招生简章

【计算机网络-哈工大】---学习笔记(下)---(二)Web安全威胁、SSL\IPsec、虚拟专用网、防火墙

【HMS core】【ML kit】机器学习服务常见问题FAQ
随机推荐
Perl basic grammar
How to choose an APS system, it is necessary to clarify these seven key factors
【HMS Core】【FAQ】【AR Engine】AR Engine常见问题合集
【luogu U142356】Suffix of the Brave (SA) (Chairman Tree) (2 points)
Address book (dynamic version) (C language) (VS)
The development trend of software testing
Openresty执行lua脚本
数据库事务&锁机制
Why do enterprises need business intelligence BI in the digital age
Pycharm社区版专业版下载安装环境配置【精细到每一个步骤】
浙江DAMA-CDGA/CDGP数据治理认证招生简章
电气规则
LN论文、五种归一化原理和实现
学习笔记_numpy图片基本操作_自用
区别如下概念:助记符、汇编语言、汇编语言程序和汇编程序。
Quantitative Genetics Heritability Calculation 2: Half Siblings and Full Siblings
dsafasfdasfasf
php write online remote file to temp file
JS-DOM-对象的事件onload、匿名函数、this
【luogu U142356】勇者的后缀(SA)(主席树)(二分)