一、函数作用
最简单的调用就是将一个数组清零,代码如下:
const int maxn = 1024; int a[maxn]; memset(a, 0, sizeof(a)); // 结果:a[0]=a[1]=a[...]=0;这里 sizeof(a) = maxn * 4 = 4096; 表示的是将数组首地址 a 开始往后的 4096 个字节,都设置为 0;
二、效率对比
直接调用 memset 接口清零 和 调用循环进行清零,进行一个测试后如下:
对长度为 10000000 的数组,执行100次调用;
模式 | memset | for |
---|---|---|
debug | 375ms | 2156ms |
release | 343ms | 329ms |
三、误区总结
1、按字节设置
memset 实现原理是根据字节来设置的,比如对于字节数组char a[100],将所有字节都设置为5,就可以调用:
memset(a, 5, sizeof(a));
但是,对于int b[100],也采用这种方法,就会导致错误:
memset(b, 5, sizeof(b));得到 b 数组中元素的值为 84215045; 为什么呢? 我们把这个数组转换成二进制,得到: ( 00000101 00000101 00000101 00000101 ) 2 (00000101 \ 0000 0101 \ 0000 0101 \ 0000 0101)_2 (00000101 00000101 00000101 00000101)2 因为 i n t int int 占据了 4 4 4 个字节,把每个字节都设置成了5,所以最后转成十进制就变成了 84215045; 同理,当类型是 short(二字节整数),或者 long long(八字节整数)都会有类似问题,总结表格如下:
总结表格如下:
memset值 | char | short | int | long long |
---|---|---|---|---|
0 | 0 | 0 | 0 | 0 |
-1 | -1 | -1 | -1 | -1 |
5 | 5 | 1285 | 84215045 | 361700864190383365 |
2、设置的值只有最低字节有效
memset(a, 0x05ffffff, sizeof(a)); memset(a, 0xffffff05, sizeof(a)); memset(a, 0xffffff08, sizeof(a)); memset(a, 0x12345678, sizeof(a));
设置值的时候,只会采用最低的字节作为赋值用,通俗的讲,就是以上四句话调用,等价于:
memset(a, 0xff, sizeof(a)); memset(a, 0x05, sizeof(a)); memset(a, 0x08, sizeof(a)); memset(a, 0x78, sizeof(a));
3、堆内存不可直接 sizeof 取首地址
在堆上申请了一个数组空间,并且想要给它初始化,调用如下:
const int maxn = 1024; int *p = new [maxn]; memset(p, 0, sizeof(p));这里进入了另一个误区,因为 p p p 在这里虽然是数组首地址,但是它扮演的角色更多的,其实是个指针,所以在进行 sizeof 运算符操作的时候,取得的值并不是 4096,而是指针的大小; 32位机子上,指针大小为4,;64位机子上,指针大小为 8; 正确做法是:
const int maxn = 1024; int *p = new [maxn]; memset(p, 0, maxn * sizeof(int));
4、传参数组不可直接 sizeof 取首地址
对传参为数组的数据进行 memset,调用如下:
void fun(int a[maxn]) { memset(a, 0, sizeof(a)); }这里调用同样是错误的,因为当数组作为传参的时候,这里的 a 已经退化为指针,所以同样不能用 sizeof 数组首地址来取大小; 正确做法是:
void fun(int a[maxn]) { memset(a, 0, maxn * sizeof(int)); }
当然,当传参是结构体指针的时候也是如此;
参考于:CSDN-英雄哪里出来https://blog.csdn.net/WhereIsHeroFrom/article/details/111660632