编写自己的memcpy()和memmove()

这个 memcpy 函数用于将数据块从源地址复制到目标地址。下面是它的原型。

null
void * memcpy(void * destination, const void * source, size_t num);

其思想是简单地将给定的地址类型转换为char*(char需要1字节)。然后一个接一个地将数据从源复制到目标。下面是这个想法的实现。

// A C implementation of memcpy()
#include<stdio.h>
#include<string.h>
void myMemCpy( void *dest, void *src, size_t n)
{
// Typecast src and dest addresses to (char *)
char *csrc = ( char *)src;
char *cdest = ( char *)dest;
// Copy contents of src[] to dest[]
for ( int i=0; i<n; i++)
cdest[i] = csrc[i];
}
// Driver program
int main()
{
char csrc[] = "GeeksforGeeks" ;
char cdest[100];
myMemCpy(cdest, csrc, strlen (csrc)+1);
printf ( "Copied string is %s" , cdest);
int isrc[] = {10, 20, 30, 40, 50};
int n = sizeof (isrc)/ sizeof (isrc[0]);
int idest[n], i;
myMemCpy(idest, isrc, sizeof (isrc));
printf ( "Copied array is " );
for (i=0; i<n; i++)
printf ( "%d " , idest[i]);
return 0;
}


输出:

Copied string is GeeksforGeeks
Copied array is 10 20 30 40 50

是什么 memmove() ?

memmove()与memcpy()类似,因为它还将数据从源复制到目标。当源地址和目标地址重叠时,memcpy()会导致问题,因为memcpy()只是将数据从一个位置逐个复制到另一个位置。例如,考虑下面的程序。

// Sample program to show that memcpy() can lose data.
#include <stdio.h>
#include <string.h>
int main()
{
char csrc[100] = "Geeksfor" ;
memcpy (csrc+5, csrc, strlen (csrc)+1);
printf ( "%s" , csrc);
return 0;
}


输出:

GeeksGeeksfor

由于输入地址重叠,上述程序会覆盖原始字符串并导致数据丢失。

// Sample program to show that memmove() is better than memcpy()
// when addresses overlap.
#include <stdio.h>
#include <string.h>
int main()
{
char csrc[100] = "Geeksfor" ;
memmove (csrc+5, csrc, strlen (csrc)+1);
printf ( "%s" , csrc);
return 0;
}


输出:

GeeksGeeksfor

如何实现memmove()?

这里的技巧是使用临时数组,而不是直接从src复制到dest。使用临时数组对于处理源地址和目标地址重叠的情况非常重要。

//C++ program to demonstrate implementation of memmove()
#include<stdio.h>
#include<string.h>
// A function to copy block of 'n' bytes from source
// address 'src' to destination address 'dest'.
void myMemMove( void *dest, void *src, size_t n)
{
// Typecast src and dest addresses to (char *)
char *csrc = ( char *)src;
char *cdest = ( char *)dest;
// Create a temporary array to hold data of src
char *temp = new char [n];
// Copy data from csrc[] to temp[]
for ( int i=0; i<n; i++)
temp[i] = csrc[i];
// Copy data from temp[] to cdest[]
for ( int i=0; i<n; i++)
cdest[i] = temp[i];
delete [] temp;
}
// Driver program
int main()
{
char csrc[100] = "Geeksfor" ;
myMemMove(csrc+5, csrc, strlen (csrc)+1);
printf ( "%s" , csrc);
return 0;
}


输出:

GeeksGeeksfor

优化: 该算法效率低下(如果使用临时数组,时间会增加一倍)。除非真的不可能,否则应该避免双重复制。

但在这种情况下,通过选择复制方向可以很容易地避免双重复制。事实上,这就是memmove()库函数的作用。

通过比较src和dst地址,您应该能够发现它们是否重叠。

–如果它们不重叠,您可以向任何方向复制 –如果它们确实重叠,找出dest的哪一端与源重叠,并相应地选择复制方向。 –如果dest的开头重叠,则从结尾复制到开头 –如果dest的结尾重叠,则从开始复制到结束 –另一个优化是按字数复制。只是要小心处理边界条件。 –由于向量指令是连续的,所以进一步的优化将是对副本使用向量指令。

本文由Saurabh Jain撰稿。如果您发现任何不正确的地方,或者您想分享有关上述主题的更多信息,请写下评论。

© 版权声明
THE END
喜欢就支持一下吧
点赞7 分享