C语言进阶篇 第三讲【内存函数的使用和剖析】

一、本章重点

内存操作函数

memcpy

memmove

memset

memcmp

上一节我们介绍的字符串函数,其操作对象是:字符串,会以'\0'结尾

那如果我们要操作整型数组,浮点型数组呢?

这里就要用到内存函数。 

二、memcpy--内存拷贝

void * memcpy ( void * destination, const void * source, size_t num );

函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。

这个函数在遇到 '\0' 的时候并不会停下来。

如果source和destination有任何的重叠,复制的结果都是未定义的。

 示例代码1:整型肤质

int arr1[] = {1,2,3,4,5};
int arr2[5] = {0};
memcpy(arr2,arr1,sizeof(arr1));

 示例代码2:结构体复制

/* memcpy example */
#include <stdio.h>
#include <string.h>
struct {
 char name[40];
 int age;
} person, person_copy;
int main ()
{
 char myname[] = "Pierre de Fermat";
 /* using memcpy to copy string: */
 memcpy ( person.name, myname, strlen(myname)+1 );
 person.age = 46;
 /* using memcpy to copy structure: */
 memcpy ( &person_copy, &person, sizeof(person) );
 printf ("person_copy: %s, %d \n", person_copy.name, person_copy.age );
 return 0;
}

注:

while(n--):先判断n是不是0。如果n不为0,n减1,执行循环体。n的变化过程:n-1~0


while(--n):n先减1,再判断n是不是0。如果n不为0,执行循环体。n的变化过程:n-1~1

 模拟实现:

void* my_memcpy(void* dest, const void* src, size_t num)
{
	void* ret = dest;
	assert(dest != NULL);
	assert(src != NULL);
	while (num--)
	{
		*(char*)dest = *(char*)src;//一个字节一个字节的访问
		++(char*)dest;
		++(char*)src;
	}
	return ret;
}

【这里存疑:如果将int型指针强制类型转换成了char*,这时候对其进行+1操作会报错:表达式必须是可修改的左值】

 解答:

写成这样即可:

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

最终代码:

void* my_memcpy(void* dest, const void* src, size_t num)
{
	void* ret = dest;
	assert(dest != NULL);
	assert(src != NULL);
	while (num--)
	{
		*(char*)dest = *(char*)src;//一个字节一个字节的访问
		dest = (char*)dest+1;
		src = (char*)src+1;
	}
	return ret;
}

三、memmove--内存移动

void * memmove ( void * destination, const void * source, size_t num );

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

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

 

如果使用上面的memcpy函数,就会出现这样的结果。

这也是memmove函数存在的理由。 

C语言标准规定,memcpy只要处理不重叠的内存拷贝即可,

memmove是处理重叠内存的拷贝。

/* memmove example */
#include <stdio.h>
#include <string.h>
int main ()
{
 char str[] = "memmove can be very useful......";
 memmove (str+20,str+15,11);
 puts (str);
 int arr[] = {1,2,3,4,5,6,7,8,9,10};
 memmove(arr+2,arr,20);
 return 0;
} 

模拟实现:

分两种情况。

1、dest落在了src的左侧:从前向后拷贝。

2、dest落在了src的右侧:从后向前拷贝。

3、dest和src不重叠:均可。

所以我们可以规定:

在src的地址前,进行从前向后移动;

在src的地址后,进行从后向前移动。

void * memmove ( void * dst, const void * src, size_t count)
{
 void * ret = dst;
 if (dst <= src || (char *)dst >= ((char *)src + count)) {
 /*
 * Non-Overlapping Buffers
 * copy from lower addresses to higher addresses
 */
 while (count--) {
 *(char *)dst = *(char *)src;
 dst = (char *)dst + 1;
 src = (char *)src + 1;
 }
 }
 else {
 /*
 * Overlapping Buffers
 * copy from higher addresses to lower addresses
 */
 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);
} 

四、memset--内存设置

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

设置缓冲区为一个特定的字符。

dest:目的地空间

c:设置的字符是什么

count:字符数量(字节数量)

示例代码:

	char arr[10] = "";
	memset(arr, '#', 10);

 注意,这个函数是一个字节一个字节的更改,所以用在字符数组里很方便。

五、memcmp--内存比较

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

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

返回值如下:

 

如果对比8个字节,那么数组2和数组1一样大,所以最终返回0.

如果对比9个字节,那么数组2会比数组1要大,所以最终返回-1.

/* memcmp example */
#include <stdio.h>
#include <string.h>
int main ()
{
 char buffer1[] = "DWgaOtP12df0";
 char buffer2[] = "DWGAOTP12DF0";
 int n;
 n=memcmp ( buffer1, buffer2, sizeof(buffer1) );
 if (n>0) printf ("'%s' is greater than '%s'.\n",buffer1,buffer2);
 else if (n<0) printf ("'%s' is less than '%s'.\n",buffer1,buffer2);
 else printf ("'%s' is the same as '%s'.\n",buffer1,buffer2);
 return 0;
} 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值