c语言,内存操作函数的秘密,空类型指针含义 memcpy,memmove,memset 解析与自主实现,内附完整代码。

在初学编程语言时,赋值语句一向被使用的很频繁,其实赋值语句就是内存函数的基本逻辑

下面我们来看一个简单赋值语句的例子:

int main()
{
    int a = 1;
    int b = 0;
    int c = 0;

    b = a;
    char* pa = (char*)&a;
    char* pc = (char*)&c;
    printf("%d %d\n", b, c);
    for (int i = 0; i < 4; i++)
    {
        *(pc + i) = *(pa + i);
    }
    printf("%d %d\n", b, c);
    return 0;
}

对于同类型变量的数据进行交换时,我们可以直接赋值 b = a;

也可以将其交给指针,在对其地址进行强制类型转换后,一个字节一个字节的进行交换。

    char* pa = (char*)&a;
    char* pc = (char*)&c;
    for (int i = 0; i < 4; i++)
    {
        *(pc + i) = *(pa + i);
    }

   for (int i = 0; i < 4; i++)

//整形变量总共四个字节,所以这里循环的交换四次,也就交换了四个字节,正好是一个整形的大小。

我们来编译看一下结果:

可以看到,直接赋值,和每个字节按顺序赋值达到的效果是相同的。 

空类型指针的作用:

 在上面的例子可以看到,将int 类型的变量取地址交给char类型的指针,虽然没有错误(因为不同变量地址的大小都是一样,不同类型指针的字节大小也是相同的)所以只是赋值的话,是可以编译的过去的。但是可以看到,编译的结果有一个警告,类型不兼容。而void类型的指针来接收int类型变量的地址时,是没有警告的。

void类型的指针,可以接受任意类型变量的地址,因为他没有具体的类型,但是他也因为没有具体类型从而不能直接进行解引用。(因为指针在没有类型的情况下,解引用不知道该访问几个字节的空间)

内存拷贝函数:memcpy();

定义形式:void *memcpy( void *dest, const void *src, size_t count );

void *dest:接收目的空间首地址的指针

const void *src:接收源空间首地址的指针

size_t count :所需要拷贝的字节个数

自主实现如下:

 完整代码如下:

void* my_memcpy(void* dest, const void* src, size_t num)
{
	assert(dest && src);
	for (int i = 0; i < num; i++)
	{
		*((char*)dest + i) = *((char*)src + i);
	}
	return dest;
}
int main()
{
	int arr1[20] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[10] = { 0 };
	my_memcpy(arr2, arr1, 20);
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", arr2[i]);
	}
	return 0;
}

我们以空类型的指针进行接受,然后将其强制类型转换成char类型的变量进行操作。再知道num(需要交换的字节个数),就可以对其进行一个字节一个字节的交换。

但是这个函数有一个缺点就是不能拷贝内存重叠情况的数据,我们来看下面一个例子

将数组arr1中前五个字节的变量(1,2,3,4,5)拷贝到arr1+2的位置上(3,4,5,6,7)

可以看到,得到的结果和我们不是我们想看到的,因为我们是从前到后的数据赋值,这样的话,因为有内存重叠的情况,所以前面赋值的数据会把后面需要复制的数据进行覆盖

 示意图如下:

所以这里就需要引入另一个函数了

memmove();

我们再来看这样的一个例子 :

将src指向的五个整形空间的数据赋值到dest指向的五个整形空间

如果我们从后向前的赋值,这样就能很好的规避后面的数据被覆盖的情况了

这样继续下去:

 当然这种情况只是适用于目的空间,比源空间的首地址大(目的空间地址在源空间地址的后面)

如果这种情况还从后向前拷贝的话,也会将后面的数据覆盖。所以这里就需要从前向后的拷贝。 

1:dest>=src(目的空间在源空间后),从后向前拷贝

 2:src>dest(源空间在目的空间后)从前向后拷贝

实现的代码如下

void* my_memmove(void* dest, const void* src, size_t num)
{
	assert(dest && src);
	if (dest >= src)
	{
		//从后向前
		while (num--)
		{
			*((char*)dest + num) = *((char*)src + num);
		}
	}
	else
	{
		//从前向后
		for (int i = 0; i < num; i++)
		{
			*((char*)dest + i) = *((char*)src + i);
		}
	}
	return dest;
}
int main()
{
	int arr[10] = { 0,1,2,3,4,5,6,7,8,9 };
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
	my_memmove(arr+2,arr,20);
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值