天天看点

内存操作函数memcpy memmove memset memcmp

1.memcpy

void * memcpy ( void * dest, const void * src, size_t num )

(1)函数memcpy从src的位置开始向后复制num个字节的数据到dest的内存位置。

(2)这个函数在遇到’\0’ 的时候并不会停下来。

(3)如果src和dest有任何的重叠,复制的结果都是未定义的 。

void *my_memcpy(void *dest, const void *src, size_t num)
{
	char *str1 = (char *)dest;//应为此函数要将src的n个字节copy给dest
	char *str2 = (char *)src;//所以先强转为char*
	assert(dest != NULL && src != NULL);//使用assert断言,防止传空指针
	while (num--)
	{
		*str1++ = *str2++;//切记不能把此条语句放入while()中,其他类型强转成char*
	}//时之间可能会存有'\0'的字节,会导致while的结束
	return dest;
}
int main()
{
	int ar[10] = { 1, 2, 3, 4 };
	int ar2[10];
	my_memcpy(ar2, ar, 4);
	printf("%d %d\n", ar2[0], ar2[1]);
    system("pause");
    return 0;
}
           

运行结果:

内存操作函数memcpy memmove memset memcmp

2. memmove

void * memmove ( void * dest, const void * src, size_t num )

(1).和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。

(2).如果源空间和目标空间出现重叠,就得使用memmove函数处理

void *my_memmove(void * dest, const void * src, size_t num)
{
	char *str1 = (char*)dest;//定一两个char*指向要处理的两个字符串的首地址
	char *str2 = (char*)src;//memmove是字节移动函数,必须强转为char*;
	assert(str1 != NULL&&str2 != NULL);//遇见指针先断言
	if (str1 <= str2 || str1 >= str2 + num)
	//以下就是对于内存重叠时和memcpy的不同之处,
	{//分为三种情况,第一种:src在低地址(一串字符串从左到右地址由高到低),dest在高地址
	 //从左到右一次移动就好,不会发生内存重叠。第二种:src在高地址,dest在低地址,
	 //但要移动的长度不足以使其反生内存重叠。
		*str1++ = *str2++;
	}
	else
	//第三种:src在高地址,dest在低地址,移动的长度正好会发生内存重叠
	{//解决方法就是由原来的从左到右移动改为从右向左移动,先把内存重叠区域的
     //字符移动走,就不会被高地址的覆盖掉。
		str1 += num - 1;//str1和str2先移动到内存重叠区域的最后一个字符上
		str2 += num - 1;
		while (num--)
		{//依次从左向右赋值
			*str1-- = *str2--;
		}
	}
}
    int main()
    {
    	char ar1[10] = "abcdef";
    	char ar2[10] = "abcdef"; 
    	char ar3[10] = "abcdef";
    	char ar4[10] = "abcdef";
    	my_memmove(ar1+2, ar1, 4);
    	printf("my_memmove ar1 = %s\n", ar1);
    	my_memmove(ar2, ar2+2, 4);
    	printf("my_memmove ar2 = %s\n", ar2);
    	my_memcpy(ar3, ar3 + 2, 4);
    	printf("my_memcpy ar3 = %s\n",ar3);
    	my_memcpy(ar4 + 2, ar4, 4);
    	printf("my_memcpy ar4 = %s\n", ar4);
        system("pause");
        return 0;
    }
           

运行结果:

内存操作函数memcpy memmove memset memcmp

由此可以看出,在对自身进行字符串处理时,遇到内存重叠,使用memcpy会更符合意想的结果。

3. memset

**void memset( void dest, int c, size_t count )

The memset function sets the first count bytes of dest to the

character c .

memset函数将dest的前count个字节全部设置为字符c。

void *my_memset(void *dest, int value, size_t count)
{
	char *tmp = (char*)dest;
	assert(tmp != NULL);
	while (count--)
	{
		*tmp++ = value;
	}
	return dest;
}
int main()
{
	char ar1[10] = "abcdef";
	my_memset(ar1, 'o', 4);
	printf(ar1);
    system("pause");
    return 0;
}
           

运行结果:

内存操作函数memcpy memmove memset memcmp

4. memcmp

int memcmp ( const void * ptr1, const void * ptr2, size_t num )

1.比较从ptr1和ptr2指针开始的num个字节

2.返回值如下

返回值 ptr1 ? ptr2
1 >
=
-1 <

注意:strcmp,strncmp和memcmp的比较

1、比较的内容不同。strcmp和strncmp只能比较字符串,而memcmp可以比较字符串,字符数组,数组等。

2、比较的方法不同。strcmp和strncmp(’\0’和num同时限制)遇到被复制字符的串结束符"\0"才结束,所以容易溢出。对于memcmp(),如果两个字符串相同而且num大于字符串长度的话,memcmp不会在\0处停下来,会继续比较\0后面的内存单元,直到ret不为零或者达到num次。(注:库函数中strncmp不会在’\0’处停下来)

int my_memcmp(const void * ptr1, const void * ptr2, size_t num)
{
	unsigned char* str1 = (unsigned char*)ptr1;
	unsigned char* str2 = (unsigned char*)ptr2;
	int  ret;
	if (!num)
	{
		return 0;
	}
	assert(str1 != NULL && str2 != NULL);
	while ((num--) && !(ret = (*str1 - *str2)))//与strcmp最大的差别,不用找'\0'
	{
		str1++;
		str2++;
	}
	if (ret > 0)
	{
	    return 1;
	} 
	else if (ret < 0)
	{
		return -1;
	}
	return 1;
}

int main()
{

	char ar1[10] = "abcdef";
	char ar2[10] = "abcd";
	printf("%d\n", my_memcmp(ar1, ar2, 5));
	printf("%d\n", my_strncmp(ar1, ar2, 5));
    system("pause");
    return 0;
    }
           

运行结果:

内存操作函数memcpy memmove memset memcmp

继续阅读