【C-memset】memset函数的深坑

一、引子


int a[4];
memset(a, 1, sizeof(a));

你觉得 a[0] 应该是多少?

你绝对想不到,输出是 16843009。

为什么?不应该是 1 么?

二、正文

1、memset函数声明

    memset(void *s,int ch,size_t n);

    将s开始的n个字节用 ch的二进制的后八位 替代并且返回s;并不是简单的将 ch 的值设置到s数组中。一般 ch 只出现 0 和 -1 两种情况,0是将内存全置为0,-1是将内存全都置为 1。其它ch值均不常用。

原因:由于int类型占4个字节,memset乖乖的给每个字节填充为 00000001,编译器一看 是个int类型,按顺序一次读取4个字节,读到的就是  00000001 0000001 0000001 0000001(就是0x01010101,也就是我们在显示器上看到的 16843009)。

如果 memset(a ,2 , 4)又会怎样呢?那么 a[0],就会是 00000010 000000010 00000010 00000010(十六进制就是0x02020202)。

2、注意:

  1. memset函数按字节对内存块进行初始化,所以不能用它将int数组初始化为0和-1之外的其他值(除非该值高字节和低字节相同)。
  2. ch接收参数的范围0-255 ,该函数只能取ch的后八位赋给你所指定的范围的每个字节,比如int a[5]赋值memset(a,-1,sizeof(int )*5)与memset(a,511,sizeof(int )*5) 所赋值的结果是一样的都为-1;因为-1的二进制码为(11111111 11111111 11111111 11111111)而511的二进制码为(00000000 00000000 00000001 11111111)后八位都为(11111111),所以数组中每个字节,如a[0]含四个字节都被赋值为(11111111),其结果为a[0](11111111 11111111 11111111 11111111),及a[0]=-1,因此无论ch多大只有后八位二进制有效,而八位二进制的范围是(0~255)。而对字符数组操作时则取后八位赋值给字符数组,其八位值作为ASCII  码。
  3. 注意n和ch的位置
  4. 不要过度使用
  5. 注意有时候的指针降级
int func(struct some *a)
{
   …
   memset(a,0,sizeof(a))
}

    此处由于指针降级导致sizeof(a)返回的是一个指针的字节数,4字节。memset一般就用于初始化内存空间,比起for来,memset是一个比较快捷的方式。

4、更多例子

char a[4];
memset(a, '1', sizeof(a));

上面是正确的例子。这时候 a[0] 是字符 '1'。

当设置 char 类型数组时,ch 可以是0 和 任意的字符,简单说因为字符刚好是一个字节, char类型数组刚好每个元素都是一个字节,正好一一对应。

下面则是错误例子。

int a[4];
memset(a, '1', sizeof(a));

这时候 a[0] 是 825307441。(想不到吧,居然不是字符‘1’的ASCII值49?)

解析:根据ASCII表,单字节字符 '1' 的二进制是 0011 0001,十进制是49,十六进制是 0x31。因为int类型占4个字节,memset函数自觉地依次将a[0]的4个字节设置为0x31,于是四个字节连起来读取,a[0]就是0x31313131,转换为十进制是825307441。

5、总结

使用memset 给 int 类型数组初始化一定要慎重,一般仅用数值 0 和 -1。若要设置其它的值,还是乖乖用 for 循环吧。

做Online Judge时,由于输入输出格式比较严,最好每步及时打桩测试。在Coding的世界,稳扎稳打,才是最节省时间的。毕竟,出现莫名其妙、毫无头绪的BUG是再平常不过的了。逐步排除才是Coding除错的真谛。

-----刷UVa232被坑有感,记录于此。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qilei2010

送我一张彩票中了平分

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值