#include <bits/stdc++.h>
using namespace std;
int a[101];
int main ()
{
	memset (a,1,sizeof (a));
	cout<<a[1]<<endl;
	return 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是一个比较快捷的方式。

3、更多例子

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除错的真谛。