C++ memset 踩坑

文章目录
一、前言
二、函数作用
三、效率对比
四、误区总结
1、按字节设置
2、设置的值只有最低字节有效
3、堆内存不可直接 sizeof 取首地址
4、传参数组不可直接 sizeof 取首地址
一、前言
memset 作为对内存初始化的函数,还是有不少坑和误区的,今天就来对这个函数作一个总结。

二、函数作用
最简单的调用就是将一个数组清零,代码如下:
const int maxn = 1024;
int a[maxn];
memset(a, 0, sizeof(a)); // a[0]=a[1]=a[…]=0;
1
2
3
这里 sizeof(a) = maxn * 4 = 4096;
表示的是将 数组首地址 a 开始往后的 4096 个字节,都设置为 0;
三、效率对比
直接调用 memset 接口清零 和 调用循环进行清零,进行一个测试后如下:
对长度为 10000000 的数组,执行100次调用;

模式 memset for
debug 375ms 2156ms
release 343ms 329ms
因为 release 版本会做各种优化,编译器发现重复执行无效逻辑就会跳过,所以不太好造数据测试,研究时间效率的时候还是参考 debug 版本(当然,软件发布的时候肯定用的是 release 版本)。
memset 无论从时间效率,还是代码整洁来看都是由于 for 循环的,当然也带来了一些容易引起误解的地方。
四、误区总结
1、按字节设置
memset 实现原理是根据字节来设置的,比如对于字节数组char a[100],将所有字节都设置为5,就可以调用:
memset(a, 5, sizeof(a));
1
但是,对于int b[100],也采用这种方法,就会导致错误:
memset(b, 5, sizeof(b));
1
得到 b 数组中元素的值为 84215045;
为什么呢?
我们把这个数组转换成二进制,得到:
( 00000101   00000101   00000101   00000101 ) 2 (00000101 \ 0000 0101 \ 0000 0101 \ 0000 0101)_2
(00000101 00000101 00000101 00000101)
2

因为 i n t intint 占据了 4 44 个字节,把每个字节都设置成了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
表格中,只有0 和 -1是正常的,因为 0 的二进制表示中,所有位都为0;-1 的二进制表示中,所有位都为 1;
特别的,当需要设置的数,对应类型的每个字节都是同一个数的时候,也可以采用 memset,比如:int 类型的 252645135(十六进制表示为:0x0f0f0f0f);
2、设置的值只有最低字节有效
memset(a, 0x05ffffff, sizeof(a));
memset(a, 0xffffff05, sizeof(a));
memset(a, 0xffffff08, sizeof(a));
memset(a, 0x12345678, sizeof(a));
1
2
3
4
设置值的时候,只会采用最低的字节作为赋值用,通俗的讲,就是以上四句话调用,等价于:
memset(a, 0xff, sizeof(a));
memset(a, 0x05, sizeof(a));
memset(a, 0x08, sizeof(a));
memset(a, 0x78, sizeof(a));
1
2
3
4
3、堆内存不可直接 sizeof 取首地址
在堆上申请了一个数组空间,并且想要给它初始化,调用如下:
const int maxn = 1024;
int *p = new [maxn];
memset(p, 0, sizeof§);
1
2
3
这里进入了另一个误区,因为 p pp 在这里虽然是数组首地址,但是它扮演的角色更多的,其实是个指针,所以在进行 sizeof 运算符操作的时候,取得的值并不是 4096,而是指针的大小;
32位机子上,指针大小为4,;64位机子上,指针大小为 8;
正确做法是:
const int maxn = 1024;
int *p = new [maxn];
memset(p, 0, maxn * sizeof(int));
1
2
3
4、传参数组不可直接 sizeof 取首地址
对传参为数组的数据进行 memset,调用如下:
void fun(int a[maxn]) {
memset(a, 0, sizeof(a));
}
1
2
3
这里调用同样是错误的,因为当数组作为传参的时候,这里的 a 已经退化为指针,所以同样不能用 sizeof 数组首地址来取大小;
正确做法是:
void fun(int a[maxn]) {
memset(a, 0, maxn * sizeof(int));
}
1
2
3
当然,当传参是结构体指针的时候也是如此;
————————————————
版权声明:本文为CSDN博主「英雄哪里出来」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/WhereIsHeroFrom/article/details/111660632

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值