【C/C++】memset方法的誤區

1、前言

memset 做爲對內存初始化的函數,仍是有很多坑和誤區的,今天就來對這個函數做一個總結。避免後期使用不當踩入坑。數組

2、函數做用

最簡單的調用就是將一個數組清零,代碼以下:函數

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;

3、效率對比

直接調用 memset 接口清零 和 調用循環進行清零,進行一個測試後以下:測試

對長度爲 10000000 的數組,執行100次調用;
模式 memset for
debug 375ms 2156ms
release 343ms 329ms
  • 由於 release 版本會作各類優化,編譯器發現重複執行無效邏輯就會跳過,因此不太好造數據測試,研究時間效率的時候仍是參考 debug 版本(固然,軟件發佈的時候確定用的是 release 版本)。
  • memset 不管從時間效率,仍是代碼整潔來看都是因爲 for 循環的,固然也帶來了一些容易引發誤解的地方。

4、誤區總結

一、按字節設置

  • 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
  • 表格中,只有0 和 -1是正常的,由於 0 的二進制表示中,全部位都爲0;-1 的二進制表示中,全部位都爲 1;
  • 特別的,當須要設置的數,對應類型的每一個字節都是同一個數的時候,也能夠採用 memset,好比:int 類型的 252645135(十六進制表示爲:0x0f0f0f0f);

二、設置的值只有最低字節有效

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));

三、堆內存不可直接 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));

四、傳參數組不可直接 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.net

相關文章
相關標籤/搜索