一、今天我们讲一讲数据拷贝
首先肯定先得写一下我的校园生活,我们从昨天开始了我们的大学军训,给我的感觉(军训还是很有意义的,但是应该在刚开学的时候进行最后,现在 军训我还十分的不习惯,严重影响我的作息),今天5点50就起床(不够睡,难受的),然后要训练一天,只有中午两个小时和晚上一会可以进行自己的安排,时间上来说是非常宝贵的,所以我们进入话题
1.首先先讲一下strcpy函数的使用和自己实现:
(一.)首先是strcpy函数的使用方法,中文解释就是,复制拷贝的意思,就是把字符从一个地方复制拷贝到另一个地方,具体作用如下代码所示:
#include<stdio.h>
int main()
{
char arr1[] = "abcdefghijk";
char arr2[20] = "abc";
strcpy(arr2, arr1);
printf("%s",arr2);
return 0;
}
以上就是strcpy函数的使用和输出结果,充分说明strcpy的作用就是把一个字符数组中的字符串给拷贝但另一个数组中(注意这个只是拷贝字符串的拷贝函数),不具有拷贝整形数组的功能。
(二.)现在我们就来看一下我们自己应该如何实现strcpy这个函数,我们先简述一下实现的原理和自己实现这个函数的时候的接收类型,就是在自己实现这个函数时应该用的格式char * strcpy ( char * destination, const char * source );这个就是我们的my_strcpy的函数接收类型,并且实现原理就是:我们从源头拷贝一份数据到目的地中如上述格式中的意思 从source到destination,但是有两个小注意点:
1.就是注意source前面有一个const,这个的意思及时保证我的源头的东西(就是我要拷贝的东西)是一个固定的值,是不会改变的值,所以为了避免源头被改变,所以我家一个const,此时就算我不小心改变了它,它也不会被改变
2.就是还要注意这个是字符型函数,所以应该用char * 类型的指针去接收,并且返回类型也是char * ;
所以具体实现和注意请看下列代码和相关注释:
#include<stdio.h>
#include<assert.h>
char* my_strcpy(char* dest, char* src)
{
assert(dest && src);
char* ret = dest;
while (*src)
{
*dest = *src;
dest++;
src++;
}
*dest = *src;
return ret;
}
int main()
{
char arr1[] = "abcdef";
char arr2[20] = "bcd";
my_strcpy(arr2, arr1);
printf("%s",arr2);
return 0;
}
上述是最简单的按照正常思路进行的编码,这样就能成功实现strcpy这个函数了,下面展示一个它的进阶版本:
#include<stdio.h>
#include<assert.h>
char* my_strcpy(char* dest, char* src)
{
assert(dest && src);
char* ret = dest;
while (*dest++ = *src++);
return ret;
}
int main()
{
char arr1[] = "abcdef";
char arr2[20] = "bcd";
my_strcpy(arr2, arr1);
printf("%s",arr2);
return 0;
}
这个代码的具体原理与上述相同只是更加的取巧一些
2.看完strcpy的实现,现在我们看一下,strncpy的实现(具体原理相同,区别就在于这个n,代表的是固定字符拷贝的意思)
(一.)这边我们先首先看一下这个库函数的具体函数接收类型, 具体类型如下char * strncpy ( char * destination, const char * source, size_t num );
1.从这个接收类型,我们可以看出它与strcpy的区别仅在于这个size_t num,别的区别没有;
2.所以这个区别有什么区别呢?这里告诉大家,区别就在于我的这strncpy函数是可以控制我想要拷贝的字符串的元素个数的,不像是strcpy,只能复制一整个,我可以控制数量;
(二.)所以接下来然我们按照接收类型来尝试一下如何实现这个函数,请看以下代码和关键注释:
#include<stdio.h>
#include<assert.h>
char* my_strncpy(char* dest, char* src, size_t num)
{
assert(dest && src);
char* ret = dest;
while (num)
{
*dest = *src;
src++;
dest++;
num--;
}
return ret;
}
int main()
{
char arr1[] = "abcdefgh";
char arr2[20] = " ";
my_strncpy(arr2, arr1, 5);
printf("%s", arr2);
return 0;
}
这个就是strncpy函数的实现,其它原路与strcpy大致相同关键就在于那个while循环中的num的个数的循环,意思主要就是只要num不为0,我就会按照要求进行相应个数的拷贝
3.讲了上述的拷贝,大家有没有发现它的使用场景是非常的局限的,只能用于字符串之类的拷贝情形,所以接下来我们学一个,万能的内容拷贝函数(memcpy)
(一.)首先我们来看一下memcpy对整形数组的拷贝:
#include<stdio.h>
int main()
{
int i = 0;
int arr1[] = { 1,2,3,4,5 };
int arr2[10] = { 0 };
memcpy(arr2, arr1, sizeof(arr1));
for (i = 0; i < 5; i++)
{
printf("%d ", arr2[i]);
}
return 0;
}
这个就是memcpy函数的基本使用,但是它不仅可以拷贝整形,它也可以拷贝结构体之类的strcpy不能拷贝的许多类型的数据
(二.)所以接下来我们看一下应该如何自己实现my_memcpy这个函数,代码如下:
#include<stdio.h>
void* my_memcpy(void* dest, const void* src, size_t num)
{
void* ret = dest;
assert(dest && src);
while(num--)
{
*(char*)dest = *(char*)src;
++(char*)dest;
++(char*)src;
}
return ret;
}
int main()
{
int i = 0;
int arr1[] = { 1,2,3,4,5 };
int arr2[5] = { 0 };
my_memcpy(arr2, arr1,sizeof(arr1));
for (i=0; i < 5; i++)
{
printf("%d ",arr2[i]);
}
return 0;
}
这个就是my_memcpy函数的实现,具体原理,注释非常明白
但是这边就又一个主要的问题:就是假如我是像把一个整形数组中的部分元素自己拷贝到自己部分元素的位置上,如果使用这个my_memcpy函数会是怎样一个情况呢?下面由图片说明问题:
这个图片就是当我想把一个数组中的元素复制到自己数组中不同位置元素是所发生的情况,举个形象的例子:就是 数组int arr[ ] = { 1,2,3,4,5,6,7,8,9,10 };我此时拷贝的是my_memcpy(arr + 2, arr, 20);把自己数组中的元素拷贝到 自己数组中,此时拷贝的内容就是如同上图所示,这个是有原因的,(原因就是当我要从数组前面开始向后拷贝的时候前面那个元素会把我后面我同时也需要拷贝的元素给覆盖掉,导致我需要的那个元素消失,此时当我再进行下一步拷贝是,此时拷贝的内容已经不再是我原来的内容,而是覆盖它的内容,所以就导致此时的第一个元素(1)会出现多次。
4.所以为了解决上述那个问题,我们就将引入本节最重要的一个代码(my_memove),这个代码就是用来解决数据拷贝时数据内容被覆盖的问题;
(一.)首先还是以int arr3[ ] = { 1,2,3,4,5,6,7,8,9,10 };my_memove(arr3+ 2,arr3, 20);为例,这边 我们需要画一个图解来方便我们理解;
1.这个的意思就是当dest在src的左边时,此时我的src(3, 4,5, 6,7)就应该从前向后拷贝,而当我的dest在src的右边时,此时我的src(3, 4,5, 6,7)就应该从后向前拷贝,只有这样拷贝我的数据内容在拷贝过程中才不会被覆盖,而当我的dest超过src,此时从前向后还是从后向前都是可以的,所以按照上述原理,我就可以得到以下代码:
#include<stdio.h>
#include<assert.h>
void* my_memmove(void* dest, void* src, size_t count)
{
void* ret = dest;
assert(dest && src);
if (dest < src)
{
while (count--)
{
*(char*)dest = *(char*)src;
++(char*)dest;
++(char*)src;
}
}
else
{
while (count--)
{
*((char*)dest + count) = *((char*)src + count);
}
}
return ret;
}
#include<stdio.h>
int main()
{
int i = 0;
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
memmove(arr + 2, arr, 20);
for (i = 0; i < 10; i++)
{
printf("%d ",arr[i]);
}
return 0;
}
根据上述原理所得的代码,所以这样我就可以通过从后向前,还是从前向后拷贝来很好的解决我的字符覆盖问题,具体讲解全在注释之中
5.所以以上就是关于各种数据拷贝函数的使用和实现
|