memset()函数

一、前言

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次调用;

模式memsetfor
debug375ms2156ms
release343ms329ms
  • 因为 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
        
       
      </span><span class="katex-html"><span class="base"><span class="strut" style="height: 1em; vertical-align: -0.25em;"></span><span class="mopen">(</span><span class="mord">0</span><span class="mord">0</span><span class="mord">0</span><span class="mord">0</span><span class="mord">0</span><span class="mord">1</span><span class="mord">0</span><span class="mord">1</span><span class="mspace">&nbsp;</span><span class="mord">0</span><span class="mord">0</span><span class="mord">0</span><span class="mord">0</span><span class="mord">0</span><span class="mord">1</span><span class="mord">0</span><span class="mord">1</span><span class="mspace">&nbsp;</span><span class="mord">0</span><span class="mord">0</span><span class="mord">0</span><span class="mord">0</span><span class="mord">0</span><span class="mord">1</span><span class="mord">0</span><span class="mord">1</span><span class="mspace">&nbsp;</span><span class="mord">0</span><span class="mord">0</span><span class="mord">0</span><span class="mord">0</span><span class="mord">0</span><span class="mord">1</span><span class="mord">0</span><span class="mord">1</span><span class="mclose"><span class="mclose">)</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height: 0.301108em;"><span class="" style="top: -2.55em; margin-left: 0em; margin-right: 0.05em;"><span class="pstrut" style="height: 2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height: 0.15em;"><span class=""></span></span></span></span></span></span></span></span></span></span></span></li><li>因为 <span class="katex--inline"><span class="katex"><span class="katex-mathml">
     
      
       
        
         i
        
        
         n
        
        
         t
        
       
       
        int
       
      
     </span><span class="katex-html"><span class="base"><span class="strut" style="height: 0.65952em; vertical-align: 0em;"></span><span class="mord mathdefault">i</span><span class="mord mathdefault">n</span><span class="mord mathdefault">t</span></span></span></span></span> 占据了 <span class="katex--inline"><span class="katex"><span class="katex-mathml">
     
      
       
        
         4
        
       
       
        4
       
      
     </span><span class="katex-html"><span class="base"><span class="strut" style="height: 0.64444em; vertical-align: 0em;"></span><span class="mord">4</span></span></span></span></span> 个字节,把每个字节都设置成了5,所以最后转成十进制就变成了 84215045;</li><li>同理,当类型是 short(二字节整数),或者 long long(八字节整数)都会有类似问题,总结表格如下:</li></ul> 
    
memset值charshortintlong long
00000
-1-1-1-1-1
55128584215045361700864190383365
  • 表格中,只有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(p));

 
 
  • 1
  • 2
  • 3
  • 这里进入了另一个误区,因为
         p
        
       
       
        p
       
      
     </span><span class="katex-html"><span class="base"><span class="strut" style="height: 0.625em; vertical-align: -0.19444em;"></span><span class="mord mathdefault">p</span></span></span></span></span> 在这里虽然是数组首地址,但是它扮演的角色更多的,其实是个指针,所以在进行 sizeof 运算符操作的时候,取得的值并不是 4096,而是指针的大小;</li><li>32位机子上,指针大小为4,;64位机子上,指针大小为 8;</li><li>正确做法是:</li></ul> 
    
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
  • 当然,当传参是结构体指针的时候也是如此;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值