在此之间,我们学过许多的字符函数,例如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个字节。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/81467.html