C语言中的memset()函数

memset()函数在C中是在string.h头文件里定义的,在C++中是在cstring头文件里定义的。
其定义是 void *memset(void *s,int c,size_t n);
功能是将内存空间 s 的前 n 个字节的值设为值 c。该函数常被用于对数组进行清零操作。
尽管变量 c 是 int 类型,但是memset是向以字节为单位的内存单元中填充值,计算机中一个内存单元的大小是一个字节,一个内存单元中能够放入的数值范围是0到0xff,所以当 c 的值大于255时,c的高16位被舍弃,只有低8位的值被填入。即填入的值是 c % 256 ,%表示求余数。
在对数组元素使用memset时特别需要注意:memset在填充时是按照字节顺序填充的,而不是按数组元素填充。用memset对字符数组赋初始值很简单,比如
char a[100];
memset(a, '\0', sizeof(a));
但是用memset对非字符型的数组赋初值时要非常小心。
例1

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int i, a[10];
for (i=0;i<10;i++)
  a[i]=0xFFFFFFFF;
for (i=0;i<10;i++)
  printf("a[%d]=0x%x\n",i,a[i]);
printf("\nAfter memset() function operation:\n");
memset(a, 100,sizeof(int));
for (i=0;i<10;i++)
  printf("a[%d]=0x%x\n",i,a[i]);
system("pause");
return 0;
}

运行这个程序后发现,只有a[0]的值被改为0x64646464,其它数组元素的值还是0xffffffff。因为十进制的100对应于0x64,int类型占4个字节,memset(a, 100,sizeof(int));这条语句将从数组a的地址(也就是第一个元素a[0]的地址 &a[0])开始,依次把4个内存单元中的值都设置为0x64,所以a[0]的值变成了0x64646464。

例2

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int i, a[10];
printf("the size of array a[] is %d bytes.\n", sizeof(a));
printf("the size of int is %d bytes.\n", sizeof(int));
for (i=0;i<10;i++)
  a[i]=0xFFFFFFFF;
for (i=0;i<10;i++)
  printf("a[%d]=0x%x\n",i,a[i]);
printf("\nAfter memset() function operation:\n");
memset(a,'0',sizeof(a));
for (i=0;i<10;i++)
  printf("a[%d]=0x%x\n",i,a[i]);
system("pause");
return 0;
}

运行这个程序后发现数组a中的每一个元素(从a[0]到a[9]),其值都被改为0x30303030。注意'0'对应的ASCII码值是48(即0x30)。

1. 如果把 memset(a,'0',sizeof(a)); 改为 memset(a,0,sizeof(a)); 则数组a中每一个元素(从a[0]到a[9])的值都被改为0。
2. memset(a,'0',sizeof(a)); 不能被改为 memset(array,0,sizeof(array)*sizeof(int)); 否则访问内存时会超出数组的边界范围。

例3

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int i, a[10];
for (i=0;i<10;i++)
  a[i]=0xFFFFFFFF;
for (i=0;i<10;i++)
  printf("a[%d]=0x%x\n",i,a[i]);
printf("\nAfter memset() function operation:\n");
memset(a,1,5);
for (i=0;i<10;i++)
  printf("a[%d]=0x%x\n",i,a[i]);
system("pause");
return 0;
}

运行这个程序后发现数组元素a[0]的值被修改为0x1010101,a[1]的值被修改为0xffffff01,a[2]到a[9]的值还是0xffffffff。
a[1]的值为什么不是被改为0x01ffffff?后面有解释。

1.  如果把 memset(a,1,5); 改为 memset(a,1,20); 则元素a[0]到a[4]的值都被改为0x1010101,a[5]到a[9]的值还是0xffffffff。
2.  如果把 memset(a,1,5); 改为 memset(a,256,20); 则元素a[0]到a[4]的值都被改为0x0,a[5]到a[9]的值还是0xffffffff。因为256的高16位被舍弃,低8位如果被单独看成一个数,这个数就是0。memset函数用0依次填充了20个内存单元。
3.  如果把 memset(a,1,5); 改为 memset(a,257,20); 则显示的结果与改为 memset(a,1,20); 后的结果是一样的,即元素a[0]到a[4]的值都被改为0x1010101,a[5]到a[9]的值还是0xffffffff。
4.  如果把 memset(a,1,5); 改为 memset(a,258,20); 则元素a[0]到a[4]的值都被改为0x2020202,a[5]到a[9]的值还是0xffffffff。

void *memset(void *s,int c,size_t n);中的 c 甚至可以是负数,举一个有点极端的例子:
例4

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int i, a[10];
for (i=0;i<10;i++)
  a[i]=0xFFFFFFFF;
for (i=0;i<10;i++)
  printf("a[%d]=0x%x\n",i,a[i]);
printf("\nAfter memset() function operation:\n");
memset(a,0x87654321,5);
printf("0x87654321=%d\n",0x87654321);
printf("0x87654321 mod 256 = %d = 0x%x\n",(0x87654321 % 256), (0x87654321 % 256));
for (i=0;i<10;i++)
  printf("a[%d]=0x%x\n",i,a[i]);
system("pause");
return 0;
}

0x87654321作为一个有符号的int类型整数时,对应于十进制的 -2023406815 。但是 memset 在填充时不管正负,只使用0x87654321的低 8 位 0x21。运行这个程序后数组元素a[0]的值被修改为0x21212121,a[1]的值被修改为0xffffff21,a[2]到a[9]的值还是0xffffffff。

前面我们都是把memset函数当成一个“黑盒子”,给它输入不同的值,观察输出结果。现在我们来打开这个“黑盒子”,看看memset函数的一个内部实现作为参考吧(不同情况下具体的实现过程可能有轻微差异,这里只是其中的一个例子):

 

void * Memset(void* buffer, int c, int count)
{
char* pvTo=(char*)buffer;
assert(buffer != NULL);
while(count-->0)
*pvTo++=(char)c;
return buffer;
}

这时再回过头看前面的例子,是不是理解得更加透彻了?

 

--------------------------------------
在运行例3程序之后,数组元素a[0]的值被修改为0x1010101,a[1]的值被修改为0xffffff01,为什么a[1]的值不是被改为0x1ffffff?
回答:这是因为Intel的CPU采用little endian方式存储数据,低地址存放最低有效字节(LSB)。memset函数填充到第5个字节位置的内存单元时,这个内存单元存放的是数组元素a[1]的低8位,而不是高8位。为了了解little endian,可以看下面的例子:
例5

#include <stdio.h>
#include <stdlib.h>
int main()
{
unsigned int a;
int i;
char *p;
a=0x12345678;
printf("a=0x%x\n",a);
p=(char *)&a;
for (i=0;i<4;i++)
  printf("p+%d=0x%x, *(p+%d)=0x%x\n", i, (p+i), i, *(p+i));
system("pause");
return 0;
}

int 类型的变量在VC中长度为4个字节,从程序运行后的显示结果可以看出,int 类型变量 a 的值放在四个内存单元中,地址从低到高的单元中依次存放0x78、0x56、0x34、0x12,这四个字节的值拼成变量a的值。

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值