[C language] Common memory function usage (detailed explanation of memcpy, memmove, memcmp and memset)

This article is to share common memory functions

The functions shared above are all related to strings, but when we operate data, we not only need to operate character data

Next, share a few functions related to memory

Table of contents

This article is to share common memory functions

1.memcpy

2.memmove

Self-defined function simulation to realize memmove function

3.memcmp

4.memset


These functions don't care what type of data needs to be copied, and this function can help you complete the task

1.memcpy

The following description of the function function is to copy num bytes of data pointed by the source pointer to the destination space,

Then go directly to the code

#include<stdio.h>
#include<string.h>
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[8] = { 0 };
	memcpy(arr2, arr1, 20);
	return 0;
}

The meaning of the above code is to copy the 20 bytes of data in arr1 to the arr2 array

Then let's debug and verify

This is the content of the arr2 array before entering the function

 go one step further

We will see that the data in the arr2 array becomes the content of 20 bytes in arr1 

Then this is the simple use of the memcpy function

So can we use this function to process floating-point data?

absolutely okay

Test the code below

void test2()
{
	float arr1[] = { 1.0,2.0,3.0,4.0,5.0 };
	float arr2[8] = { 0 };
	memcpy(arr2,arr1,12);
}
int main()
{
	test2();
	return 0;
}

We replaced the data of the integer type with the data of the floating point type

debug it

 You can see that the arr2 array has been initialized;

go one step further down;

 At this point we will see the 12 bytes of data in arr1, that is, the first three data have been copied to the arr2 array 

So we just know that the memcpy function doesn't care what data type is copied, it only copies how many bytes of data.

Then let's look back at the starting address of the target space when the function parameter and return type are used. The parameter is a pointer of type void*, so we have also learned that the pointer of type void* is actually a general type, which can accept the address of any type of data. , which is why the memcpy function can copy any type of data.

Then we might as well customize our own function to simulate a memcpy function

void* my_memcpy(void* dest,const void* src,size_t num)
{


void test3()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[8] = { 0 };
	my_memcpy(arr2,arr1,20);
}
int main()
{
	test3();
	return 0;  
}

Then this main function is not difficult for everyone to understand;

The void* type pointer dest points to the address of the first element in the arr2 array, the second parameter void* type pointer src points to the address of the first element in the arr1 array, and the third parameter is an integer parameter meaning to pass 20 words Festival;

Next, when we think of the copied content, we can directly unpack and apply it as follows:

But we will see that the compiler will report an error

What I want to explain here is that the pointer of void* type cannot be directly decomposed, but it must be converted into the type you want to convert into

However, this function should consider various types when copying, and if you want to copy the int type when using it, but enter 7 in the third parameter of the function, every time you process int type data It will process 4 bytes, so the second processing will process 8 bytes of data, which exceeds 7 bytes, so we might as well convert it into a pointer of char* type, so that it only processes one word at a time section data, and apply the solution to

The code becomes like this

But writing it like this will still make an error;

Because such forced type conversion only temporarily changes its type, it may become a void* type pointer when the function needs to be called again, and errors will occur, so we optimize it

void* my_memcpy(void* dest,const void* src,size_t num)
{
        *(char*)dest = *(char*)src;
		dest = (char*)dest + 1;
		src = (char*)src + 1;
}

 Then the advantage of writing this way is that we can save the type after the forced conversion and assign it to dest. This way of writing is perfect;

Then this can only be processed once, we have to process num bytes of data, we might as well add a while loop,

void* my_memcpy(void* dest,const void* src,size_t num)
{
	while (num--)
	{
		*(char*)dest = *(char*)src;
		dest = (char*)dest + 1;
		src = (char*)src + 1;
	}

}

Finally, a return value needs to be added, which must be of void* type, but at this time dest is already far away from the starting position with the conversion of the mandatory type, so we might as well create another pointer variable at the beginning of the function body to start it location saved

void* my_memcpy(void* dest,const void* src,size_t num)
{
	void* p = dest;
	while (num--)
	{
		*(char*)dest = *(char*)src;
		dest = (char*)dest + 1;
		src = (char*)src + 1;
	}
	return dest;
}

 Let the code debug

 You can see that the first 20 bytes of data in the arr2 array have been changed

Then it will be a good choice to use memcpy directly to copy what content you want to copy in the future;

However, when we want to copy strings, it is better to use strcpy, because there is an operation in the memcpy function that is a type of strong conversion, and it will waste a lot of time if we process a lot of data, so try to use the most matching function .

When we use memcpy, something like the following happens;

void test4()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	memcpy(arr1+2,arr1,20);

}
int main()
{
	test4();
	return 0;  
}

The purpose of my writing this code is to make the memcpy function copy from the third number; let 3, 4, 5, 6, 7 become 1, 2, 3, 4, 5

 But we debugged and saw that the elements in the arr1 array did not change as we imagined

So what is the principle?

When we copy the content, we will also change the content in arr1 at the same time, so it is equivalent to copying the content in the arr1 array to the arr1 array while changing the content, and only copy the content of 20 bytes, so the changed arr1 The content is 1, 2, 1, 2, 3, 4, 5, 6, 7, 8, we copied the content of the first 20 bytes to the content after arr+2, so it became an array as shown in the figure above content

 So we found that using memcpy may achieve unexpected consequences when memory overlaps;

It is recommended to use the memmove function in the case of memory overlap

2.memmove

From the function name, you may feel that it has nothing to do with the memcpy just now

But let's observe from the c++ official website

 Its return type is completely consistent with the type van♂ of the function parameter;

 At this time, using the memmove function will find that the purpose we mentioned above can be achieved

then we might as well

Self-defined function simulation to realize memmove function

So it's still the same, let's go step by step,

First write the function return type and return parameters

void* my_memmove(void* dest, void* src, size_t num)
{

}

analyze again

We want to start from 3 in the arr1 array, count 20 bytes of elements, and overwrite them with the elements of the original array in arr1,

Since we will overwrite part of the previous data when we use memcpy to copy, we might as well copy other data from the back first, and then copy the previous data.

But we have to discuss the situation

Still following the example of the above array, what if we want to copy 3, 4, 5, 6, and 7 in the arr1 array to the positions of the first five elements? That is to copy from front to back;

So we have to discuss it on a case-by-case basis

How to distinguish between the two situations? Draw a simple picture for everyone

 The first case is to put the data in the blue box into the red box, which requires copying the data from the back to the front

The second case is to put the blue box into the red box. In this case, the data needs to be copied from front to back

For the first type, we compare the function parameters, the data comes from the src pointer, and the destination is dest;

 The second case is as follows

 So you can use the if statement to judge

if(dest<src)
从前向后
else 
从后向前

So how does the collective

In fact, if you observe carefully, you will find that the front-to-back method is no different from memcpy, and you can cut it directly

void* my_memmove(void* dest, void* src, size_t num)
{
    if(dest<src)
    {
            while (num--)
	    {
		    *(char*)dest = *(char*)src;
		    dest = (char*)dest + 1;
		    src = (char*)src + 1;
	    }
    }
    else 
    从后向前
}

Looping from back to front is still while(num--)

Since we are copying from the back to the front, we need to access the address of the last number, then we might as well add num to the address of the first element; num starts at 20 and enters the loop, num-- becomes 19, dest It is the starting address 0, plus num is equal to 19, which is the 20th element in the array and the last element, then we have accessed the address of the last element in this way

*((char*)dest + num) = *((char*)src + num);

We might as well apply this address and assign the pointer to src, that is, the pointer to the original array, to the target space, so that the operation of assigning the value of the source space to the target address is completed, and the while loop is still required

Of course, the return value of the function is a pointer type, pointing to the first element of the array, so it is still necessary to redefine a pointer variable to store the first address, and return it at the end of the function.

The final code is as follows

void* my_memmove(void* dest, void* src, size_t num)
{
    void* ret = dest;
	if (dest < src)//从前往后
	{
		while (num--)
		{
			*(char*)dest = *(char*)src;
			dest = (char*)dest + 1;
			src = (char*)src + 1;
		}
	}
	else//从后往前
		while (num--)
		{
			*((char*)dest + num) = *((char*)src + num);
		}
    return ret;

}

 Then when the final debugging results come out, you can also see that 1 2 3 4 5 has been successfully placed in the position of 3 4 5 6 7,

Let's change the position of the actual parameter content of the function

The monitored content has also been obtained, and we copied the latter content to the front

The difference between memcpy and memmove is easy to understand

memcpy copies non-overlapping memory

memmove can copy overlapping memory

Of course, it can also be roughly understood that the range used by memmove is greater than that of memcpy

3.memcmp

Then this function may be guessed by everyone, it is to compare two pieces of memory

 Its return type is an integer of type int, and its parameters are two pointers of any type (because it does not know what type of memory to compare), and a size_t (unsigned integer) type of bytes;

The comparison is num bytes starting from the ptr1 and ptr2 pointers;

That is also similar to the strcmp function, such as the following table

The memory pointed to by the ptr1 pointer is less than the data in the memory pointed to by the ptr2 pointer, and returns a value less than zero;

Otherwise, return a value greater than 0; return zero if equal

 The code is simple to use

  At this time, the data of the first 16 bytes is compared, that is, 1 2 3 4 is equal up and down, and returns 0;

Modify the object of comparison

 At this time, 17 bytes of data are compared, so how to compare with one more byte?

It is necessary to mention the big-endian storage method and the small-endian storage method that we have learned

In the environment of vs, it is a little-endian storage method (low-order byte data is stored in a high address, and high-order byte data is stored in a low address),

We display the contents of the content array

 Then the seventeenth bit is compared with 05 and 06, and the return value is a number less than zero;

4.memset

We have contacted memset before

 Learn about the return type and parameters of this function;

It is not difficult to see that the return parameter is void* type, the first parameter is a pointer of void* type, the second parameter is int type, and the third is an unsigned integer;

Its function is to change the content of num bytes into value in the array pointed to by the first parameter.

The simple use code is as follows

#include<stdio.h>
int main()
{
	char arr[] = "hello world";
	memset(arr, 'x', 5);
	printf("%s\n",arr);
	return 0;
}

 You can see that "hello world" has become "xxxxx world"

Then the role of this string is to change the first 5 elements in the arr array to x, which should not be difficult to understand through simple use of code.

The only thing to note about this function is that the last parameter is set in bytes.

So what if you want to change the array and change all the elements of the array to 1?

 It is a pity that the elements in the array cannot be changed to 1, because memset operates in bytes, so the compiler will regard 01 01 01 01 as an integer, and we will print it out in decimal

 We see that it is a very large number; so memset cannot be used to set the contents of an integer array

The above is the content of the memory function to be shared, I hope it will be helpful to you

Guess you like

Origin blog.csdn.net/wangduduniubi/article/details/129560860