C/C++ memset方法的誤區(qū)
一、函數(shù)作用
最簡單的調(diào)用就是將一個數(shù)組清零,代碼如下:
const int maxn = 1024; int a[maxn]; memset(a, 0, sizeof(a)); // 結(jié)果:a[0]=a[1]=a[...]=0;
- 這里 sizeof(a) = maxn * 4 = 4096;
- 表示的是將數(shù)組首地址 a 開始往后的 4096 個字節(jié),都設(shè)置為 0;
二、效率對比
直接調(diào)用 memset 接口清零 和 調(diào)用循環(huán)進行清零,進行一個測試后如下:
對長度為 10000000 的數(shù)組,執(zhí)行100次調(diào)用;
模式 | memset | for |
---|---|---|
debug | 375ms | 2156ms |
release | 343ms | 329ms |
- 因為 release 版本會做各種優(yōu)化,編譯器發(fā)現(xiàn)重復(fù)執(zhí)行無效邏輯就會跳過,所以不太好造數(shù)據(jù)測試,研究時間效率的時候還是參考 debug 版本(當(dāng)然,軟件發(fā)布的時候肯定用的是 release 版本)。
- memset 無論從時間效率,還是代碼整潔來看都是由于 for 循環(huán)的,當(dāng)然也帶來了一些容易引起誤解的地方。
三、誤區(qū)總結(jié)
1、按字節(jié)設(shè)置
memset 實現(xiàn)原理是根據(jù)字節(jié)來設(shè)置的,比如對于字節(jié)數(shù)組char a[100],將所有字節(jié)都設(shè)置為5,就可以調(diào)用:
memset(a, 5, sizeof(a));
但是,對于int b[100],也采用這種方法,就會導(dǎo)致錯誤:
memset(b, 5, sizeof(b));
- 得到 b 數(shù)組中元素的值為 84215045;
- 為什么呢?
- 我們把這個數(shù)組轉(zhuǎn)換成二進制,得到:
- ( 00000101 00000101 00000101 00000101 ) 2 (00000101 \ 0000 0101 \ 0000 0101 \ 0000 0101)_2 (00000101 00000101 00000101 00000101)2
- 因為 i n t int int 占據(jù)了 4 4 4 個字節(jié),把每個字節(jié)都設(shè)置成了5,所以最后轉(zhuǎn)成十進制就變成了 84215045;
- 同理,當(dāng)類型是 short(二字節(jié)整數(shù)),或者 long long(八字節(jié)整數(shù))都會有類似問題,總結(jié)表格如下:
總結(jié)表格如下:
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;
- 特別的,當(dāng)需要設(shè)置的數(shù),對應(yīng)類型的每個字節(jié)都是同一個數(shù)的時候,也可以采用 memset,比如:int 類型的 252645135(十六進制表示為:0x0f0f0f0f);
2、設(shè)置的值只有最低字節(jié)有效
memset(a, 0x05ffffff, sizeof(a)); memset(a, 0xffffff05, sizeof(a)); memset(a, 0xffffff08, sizeof(a)); memset(a, 0x12345678, sizeof(a));
設(shè)置值的時候,只會采用最低的字節(jié)作為賦值用,通俗的講,就是以上四句話調(diào)用,等價于:
memset(a, 0xff, sizeof(a)); memset(a, 0x05, sizeof(a)); memset(a, 0x08, sizeof(a)); memset(a, 0x78, sizeof(a));
3、堆內(nèi)存不可直接 sizeof 取首地址
在堆上申請了一個數(shù)組空間,并且想要給它初始化,調(diào)用如下:
const int maxn = 1024; int *p = new [maxn]; memset(p, 0, sizeof(p));
- 這里進入了另一個誤區(qū),因為 p p p 在這里雖然是數(shù)組首地址,但是它扮演的角色更多的,其實是個指針,所以在進行 sizeof 運算符操作的時候,取得的值并不是 4096,而是指針的大??;
- 32位機子上,指針大小為4,;64位機子上,指針大小為 8;
- 正確做法是:
const int maxn = 1024; int *p = new [maxn]; memset(p, 0, maxn * sizeof(int));
4、傳參數(shù)組不可直接 sizeof 取首地址
對傳參為數(shù)組的數(shù)據(jù)進行 memset,調(diào)用如下:
void fun(int a[maxn]) { memset(a, 0, sizeof(a)); }
- 這里調(diào)用同樣是錯誤的,因為當(dāng)數(shù)組作為傳參的時候,這里的 a 已經(jīng)退化為指針,所以同樣不能用 sizeof 數(shù)組首地址來取大??;
- 正確做法是:
void fun(int a[maxn]) { memset(a, 0, maxn * sizeof(int)); }
當(dāng)然,當(dāng)傳參是結(jié)構(gòu)體指針的時候也是如此;
參考于:CSDN-英雄哪里出來https://blog.csdn.net/WhereIsHeroFrom/article/details/111660632
到此這篇關(guān)于C/C++ memset方法的誤區(qū)的文章就介紹到這了,更多相關(guān)C++ memset方法內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語言 深入探究動態(tài)規(guī)劃之區(qū)間DP
這幾天在做有關(guān)dp的題,看到一個石子合并的問題,本來以為是個貪心,后來仔細一想壓根不是貪心。貪心算法的思路是每次都取最大的,然而石子合并問題有個限制條件就是每次只能取相鄰的,這就決定了它不是個貪心2022-04-04如何基于 Blueprint 在游戲中創(chuàng)建實時音視頻功能
我們在本文先來講講如何在 Unreal 中用 Blueprint 快速實現(xiàn)。稍后會分享基于 C++的實現(xiàn)步驟。感興趣的朋友跟隨小編一起看看吧2020-05-05C++獲取類的成員函數(shù)的函數(shù)指針詳解及實例代碼
這篇文章主要介紹了C++獲取類的成員函數(shù)的函數(shù)指針詳解及實例代碼的相關(guān)資料,需要的朋友可以參考下2017-02-02C++ 數(shù)據(jù)結(jié)構(gòu)二叉樹(前序/中序/后序遞歸、非遞歸遍歷)
這篇文章主要介紹了C++ 數(shù)據(jù)結(jié)構(gòu)二叉樹(前序/中序/后序遞歸、非遞歸遍歷)的相關(guān)資料,這里提供實例代碼來幫助大家理解掌握二叉樹,需要的朋友可以參考下2017-07-07