Prototype: void*memcpy (void*dest, const void*src,unsigned int count);
Function: the memory area referred to by SRC is copied from count bytes to the memory area of Dest.
Description: The memory area referred to by SRC and dest cannot overlap, and the function returns a pointer to Dest.
Example:
//memcpy.c#include <stdlib.h>#include<string.h>Main () {Char*s="Golden Global View"; Chard[ -]; CLRSCR (); memcpy (D,s,strlen (s)); D[strlen (s)]=0; printf ("%s", D); GetChar (); return 0; }
This function is implemented by itself
Program Listing 1 Version V0.1
void Mymemmove (char *dst,char *src,int count) { while (count-- ) *dst++ = *src++; }
Program Listing 2 Testing V0.1 use Cases
void Test () { char p1[256 ] =" hello,world! "; char p2[256 ] = {0 }; Mymemmove (P2,p1,strlen (p1)); printf ("%s", p2); }
Objectively speaking, compared to those has failed or function declaration will not write the classmate, can write this code of the classmate has been very good, at least in the C language This course has reached the current educational goals of the university, but from the requirements of the enterprise personnel have a certain distance. We might as well refer to the above procedure as the V0.1 version to see if there is any place to improve.
First we see whether the function declaration is reasonable, the V0.1 version of the program will be the source address and the destination address is a char * to express, so of course there is no problem, but it is inconvenient for others to use, If you want to move the count continuous structure object to another place now, if you want to use the v0.1 program, the correct wording is as follows:
Mymemmove ((char *) DST, (char *) SRC, sizeof (thestruct) *count)
that is, we need to cast the struct pointer to char * in order to work properly, so that except for the string of other types are inevitably to be cast by the pointer, otherwise the compiler will be a quack, For example, this error occurs under vc++2008:
Error c2664: ' mymemmove ': cannot convert parameter 1 from ' thestruct * ' to ' char * '; So how do we solve this problem? It is very simple, we know there is a special pointer, any type of pointer can be assigned to it, that is void *, so the source address and destination address should be used void* to represent. Of course, the contents of the function body should be changed accordingly, so that we get the V0.2 version of the program.
Program Listing 3 V0.2 version of program
void mymemmove (void *dst,void *src,int count) { /span>while (Count-- * (char *) DST = * (char *) Src DST = (char *) DST + 1 ; src = (char *) src + 1 ; } }
Some students may ask, is there a pointer cast in this? It's just a change of place. Yes, the force pointer conversion is actually transferred from the user's code to the library's code, but we can understand mymemmove as a library, and the test as a user, in fact, through the effect of adjustment after the difference, V0.1 is a Yi Yong, and V0.2 is once and for all!
There are a few more details to note that we should also change the return value to void * In order to implement a chained expression. Also, if we accidentally will "* (char *) DST = * (char *) src;" Written in reverse, written as "* (char *) src =* (char *) DST;" Compilation still passes, and it takes time to find this error. Note that the content pointed to by SRC should not be changed within this function, and all values assigned to SRC should be forbidden, so this parameter should be modified with a const, if a similar error can be found at compile time:
Error C3892: ' src ': cannot assign to a variable it is const, as programmers make mistakes, but we can use the relatively difficult to make mistakes of the machine, which is the compiler to reduce the probability of making mistakes, so we get The V0.3 version of the program.
Program Listing 4 Version V0.3
void* Mymemmove (void*DST,Const void*SRC,intcount) { void*ret=DST; while(count--) { *(Char*) DST = * (Char*) src; DST= (Char*) DST +1; SRC= (Char*) SRC +1; } returnret; }
Now consider such a situation, there are users to call the library: Mymemmove (NULL,SRC, Count), this is completely possible, because these addresses are generally calculated by the program, it will inevitably be wrong, there are 0 addresses or other illegal address is not surprising. Predictably, if this happens, the program will be down immediately, and worse, you don't know where the error is, so you have to devote a lot of effort to finding bugs in the vast code. The common way to solve such problems is to check the input parameters for legality, that is, the V0.4 version of the program.
Program Listing 5 version V0.4
void* Mymemmove (void*DST,Const void*SRC,intcount) { void*ret=DST; if(null==dst| | NULL = =src) { returnDST; } while(count--) { *(Char*) DST = * (Char*) src; DST= (Char*) DST +1; SRC= (Char*) SRC +1; } returnret; }
The above is written as "if (null==dst| | Null ==SRC) "instead of being written as" if (DST = = NULL | | src = = NULL) "is also to reduce the probability of making a mistake. We know that in the c language "= =" and "=" are all valid operators, if we accidentally write "if (DST = null | | src = NULL)" or can be compiled through, but the meaning is completely different, but if written as "if" (null=dst| | NULL =src) ", then compile the time will not pass, so we have to develop good programming habits: constants and variables to make conditional judgments should be written in front of the constant. V0.4 version of the code first to check the validity of the parameters, if not legal to return directly, so although the possibility of the program Dwon down, but the performance is greatly reduced, because each call will be a judgment, especially frequent calls and performance requirements of high occasions, it can not be underestimated in the performance of the loss. If the long-term rigorous testing can ensure that the user does not use the 0 address as a parameter to call the Mymemmove function, you would like to have a simple way to turn off parameter legality check. We know that the macro has the function of this switch, so the V0.5 version of the program is out.
Program Listing 6 version V0.5
void* Mymemmove (void*DST,Const void*SRC,intcount) { void*ret=DST; #ifdef DEBUGif(null==dst| | NULL = =src) { returnDST; } #endif while(count--) { *(Char*) DST = * (Char*) src; DST= (Char*) DST +1; SRC= (Char*) SRC +1; } returnret; }
If we add the "#defineDEBUG" statement to enhance the robustness of the program while debugging, then we will change the "#undef debug" statement after debugging, to improve the performance of the program. In fact, there is already a similar function in the standard library of macros: Assert, and more useful, it can also be defined in the debug code on the line to check the failure, and in the absence of a definition of debug can completely treat it as non-existent. The use of ASSERT (_expression) is very simple, when the _expression is 0 o'clock, the debugger can have a debug error, with this good thing code is much easier.
Program Listing 7 version V0.6
void* Mymemmove (void*DST,Const void*SRC,intcount) {assert (DST); ASSERT (SRC); void*ret=DST; while(count--) { *(Char*) DST = * (Char*) src; DST= (Char*) DST +1; SRC= (Char*) SRC +1; } returnret; }
So far, at the language level, our program is basically no problem, so is there really no problem? This requires the programmer to think logically, which is also a good programmer must have the quality, that is the rigor of thinking, or the program will have a very hidden bug, in this case, if the user with the following code to invoke your program.
Program Listing 8 Overlapping memory tests
void Test () { char p [256 ]= " hello,world! " ; Mymemmove (P +1 , P,strlen (p) +1 Span style= "color: #000000"); printf ( " %s\n " ,p); }
If you have a computer, you can try it, you will find that the output is not the "hhello,world!" we expect. (In the "Hello world! "Before adding a h", but "hhhhhhhhhhhhhh", what is the reason? The reason is that the source address range and destination address range overlap, V0.6 version of the program inadvertently will be the source address interval content modified! Some of the quick students will say I started copying from high address. Roughly, it seems to solve the problem, although the interval is overlapping, but has been copied before the change, so does not affect the results. But to think carefully, this is actually the same as the above the thinking of the error is not rigorous, because the user such a call or error:
Mymemmove (P, p+1, strlen (p) +1); So the most perfect solution is to determine the source address and destination address size, before deciding whether to start from the high address copy or low address start copy, so V0.7 smoothly Cheng Zhang out.
Program Listing 9 version V0.7
void* Mymemmove (void*DST,Const void*SRC,intcount) {assert (DST); ASSERT (SRC); void* ret =DST; if(DST <= src | | (Char*) DST >= (Char*) SRC +count)) { while(count--) { *(Char*) DST = * (Char*) src; DST= (Char*) DST +1; SRC= (Char*) SRC +1; } } Else{DST= (Char*) DST + count-1; SRC= (Char*) SRC + count-1; while(count--) { *(Char*) DST = * (Char*) src; DST= (Char*) DST-1; SRC= (Char*) src-1; } } return(ret); }
After the revision of the above 7 revisions, our program can finally be regarded as "industrial grade". Looking back at the previous test case, you will find that it is not even a test case, because it only calls the most normal one situation, does not reach the goal of testing. With the experience above, the test cases appear accordingly, and we might as well use a character array to simulate memory.
Program Listing 10 a relatively comprehensive test case
voidTest () {Charp1[ the] ="hello,world!"; Charp2[ the] = {0}; Mymemmove (P2,p1,strlen (p1)+1); printf ("%s\n", p2); Mymemmove (Null,p1,strlen (p1)+1); Mymemmove (P2,null,strlen (p1)+1); Mymemmove (P1+1, P1,strlen (p1) +1); printf ("%s\n", p1); Mymemmove (P1,p1+1, strlen (p1) +1); printf ("%s\n", p1); }
void* MEMCPY (void* DST,Const void*src,size_t count) { void* ret =DST; while(count--) { *(Char*) DST = * (Char*) src; DST= (Char*) DST +1; SRC= (Char*) SRC +1; } return(ret); } Char*strcpy (Char*des,Const Char*src) {Assert (des! = NULL) && (src! =NULL)); Char*ret = des;//prevent changes to des addresses while((*des++ = *src++)! =' /') ; returnret; }
Citation Link: Copyright notice: This article for Bo Master original article, without Bo Master permission not reproduced. In-memory copy function (c + + memcpy) in C + +
In-memory copy function (c + + memcpy) in C + +