03-C language advanced-simulate the realization of memory operation functions (memmove and memcpy)


memcpy and memmove are not string manipulation functions, but memory manipulation functions, and there are many situations in which memory is copied and moved. The following two functions are implemented through simulation to discuss the different situations of the two pieces of memory and the memory manipulation functions The difference is that the content of this section is difficult to express clearly in words. If you have any questions or do not understand, you can leave a message to discuss!

1.The difference between memcpy and memmove

First, check the official documentation of the C language to distinguish the difference between the two functions. For English translation with translation software, you can directly see the summary.
Insert picture description here
Translation:

  • Copy the value of num bytes from the location pointed to by the source directly to the memory block pointed to by the target.
  • The underlying type of the object pointed to by the source pointer and target pointer has nothing to do with this function; the result is a binary copy of the data.
  • This function does not check any terminating null characters in the source file-it always copies num bytes accurately.
  • In order to avoid overflow, the size of the array pointed to by the target and source parameters should be at least num bytes, and should not overlap (memmove is a safer method for overlapping memory blocks).
    Insert picture description here
    translation:
  • Copy the value of num bytes from the location pointed to by the source to the memory block pointed to by the target. Copying is performed as if an intermediate buffer is used, allowing the target and source to overlap.
  • The basic type of the object pointed to by the source and target pointers has nothing to do with this function; the result is a binary copy of the data.
  • This function does not check any terminating null characters in the source file-it always copies num bytes accurately.
    To avoid overflow, the size of the array pointed to by the target and source parameters should be at least num bytes.
    Summary: Simply put, the difference between the two is that memcpy does not consider memory overlap, while memmove considers memory overlap. The following are several overlapping ways of memory blocks
    Insert picture description here

2. Simulate the realization of memcopy

First constructor

  • memcpy return type is void *
  • Copy src to dst, so src is of const type
//1.模拟实现memcpy
void * my_memcpy(void * dst, const void * src, size_t num)
{
    
    
	//判断指针合法性
	assert(dst != NULL);
	assert(src != NULL);

	//将void *强制类型转为char *,方便按字节拷贝
	char *_dst = (char *)dst;
	const char * _src = (const char *)src;

	//拷贝num个字节
	while (num)
	{
    
    
		*_dst = *_src;
		_dst++;
		_src++;
		num--;
	}

	return dst;


}

This function cannot deal with memory overlap, as shown below

int main()
{
    
    
	//内存重叠
	char buf[16] = "abcdef";
	my_memcpy(buf + 1, buf, strlen(buf)+1);
	printf("%s\n", buf);
	system("pause");
	return 0;
}

As a result,
Insert picture description here
all a is in the copy because when copying from left to right, the character on the left will be overwritten by a every time.
Insert picture description here

3. Simulation to achieve memmove

Insert picture description here
The above four situations will occur when memory overlaps:
1. The starting position of dst is to the left of the starting position of src, and the two pieces of memory are of equal size . When copying from left to right, the previous character of src will be copied to the dst character each time , So it will not be overwritten by the same character.
2. The starting position of dst is to the left of the starting position of src, and the memory block of dst is larger than the memory block of src. When copying from left to right, the previous character of src will be copied to the dst character every time, so it will not It is overwritten by the same character.
3. The starting position of src dst in the right starting position, and dst is greater than or equal src memory block of the memory block , when copying from left to right, the first character of a src repeated cover every character of dst , In the end, the whole a situation appears. So this situation needs to be copied from right to left!
4. If the dst memory block is smaller than the src memory block, this will not happen because the target memory is smaller than the copied memory, and overflow occurs!
to sum up:

  • 1,2 can be regarded as a situation, because copying from left to right will not cause problems
  • 3 can be regarded as a situation

Realization idea:
Insert picture description here
Assuming that the left is the low address and the right is the high address, then case 3 can be expressed like this

  • dst > src && src+len(src)
    • dst> src, indicating that the starting position of dst is to the right of the starting position of src
    • dst <src+len(src), which means that the start position of dst is less than the end position of src
    • && In the two cases, the logical AND indicates that the start position of dst must be in the middle of the start position and the end position of src . Simply put, dst and src overlap! ! ! . When using the memory operation function, the space of dst must be greater than or equal to the space of src, so don't worry about the entire space of dst falling in the space of src, that is, the situation in the figure below will not appear!
      Insert picture description here
      Code
//2.模拟实现memmove
void *my_memmove(void *dst, const void *src, size_t num)
{
    
    
	//判断指针合法性
	assert(dst != NULL);
	assert(src != NULL);

	//将void *强制类型转为char *,方便按字节拷贝
	char *_dst = (char *)dst;
	const char * _src = (const char *)src;

	//情况3从右向左拷贝
	if (_dst > _src && _dst < _src + num)
	{
    
    
		//首先让dst与src指向最右边
		_dst = _dst + num - 1;
		_src = _src + num - 1;

		//拷贝num个字节
		while (num)
		{
    
    
			*_dst = *_src;
			_dst--;
			_src--;
			num--;
		}
	}
	//其他情况全部从左向右拷贝
	else
	{
    
    
		//拷贝num个字节
		while (num)
		{
    
    
			*_dst = *_src;
			_dst++;
			_src++;
			num--;
		}
	}

	return dst;
}

Verify memory overlap

int main()
{
    
    
	//内存重叠
	char buf[16] = "abcdef";
	my_memmove(buf + 1, buf, strlen(buf) + 1);
	printf("%s\n", buf);
	system("pause");
	return 0;
}

The result is
Insert picture description here
perfect

4. Practice to verify whether there is a difference between the memory operation functions in the library functions

The blogger uses the win10 64-bit operating system, and VS2015 has
Insert picture description here
passed the laboratory verification. As shown in the figure above, there is no difference between the library functions memcpy and memmove of the vs2015 version. The reason may be that the memcpy function has been optimized and there will be no memory overlap error!

Guess you like

Origin blog.csdn.net/qq_40076022/article/details/110497156