1. 程式人生 > >透徹分析C/C++中memset函式(轉載只為查閱方便,若有侵權立刪)

透徹分析C/C++中memset函式(轉載只為查閱方便,若有侵權立刪)

透徹分析C/C++中memset函式

 

    在C語言中,經常需要對記憶體進行操作,裡面涉及很多函式,但是memset函式的使用有一點需要大家格外注意,這也是我在做專案時遇到過的一個問題,除錯了很久才找出來錯誤。

 

    函式原型是:void *memset(void *s, int ch, size_t n);


    函式功能是:將s所指向的某一塊記憶體中的前n個位元組的內容全部設定為ch指定的ASCII值, 第一個值為指定的記憶體地址,塊的大小由第三個引數指定,這個函式通常為新申請的記憶體做初始化工作, 其返回值為指向s的指標,它是對較大的結構體或陣列進行清零操作的一種最快方法。

 

    標頭檔案是:<memory.h>或<string.h>

 

    這些解釋在百度裡面隨處可見,而這裡需要強調的是一些需要引起大家重視的關鍵點。

 

    1. 基本應用場合

 

    memset函式通常用來對一塊已經分配地址的記憶體進行初始化,並且通常初始化為0或者字元'\0'(實際上是一樣的)。下面是一些常見例子。

 

 
  1. /*===注意:這些例子如果同時執行需要在C++編譯環境下===*/

  2. int i = 0;

  3. // 例1:對字元陣列進行初始化

  4. char buf[10];

  5. memset(buf, '\0', sizeof(char) * 10); // 0或者'\0'是等價的

  6. for (i = 0; i < 10; ++i)

  7. {

  8. printf("%c", buf[i]);

  9. }

  10. printf("\n");

  11.  
  12. // 例2:對字元指標所指區域初始化,必須已經分配記憶體

  13. char* pBuf = (char *)malloc(sizeof(char) * 10);

  14.  
  15. if (pBuf != NULL)

  16. {

  17. memset(pBuf, 0, sizeof(char) * 10); // 0或者'\0'是等價的

  18. for (i = 0; i < 10; ++i)

  19. {

  20. printf("%c", pBuf[i]);

  21. }

  22. printf("\n");

  23.  
  24. free(pBuf);

  25. pBuf = NULL;

  26. }

  27.  
  28. // 例3:對整型陣列進行初始化

  29. int iBuf[10];

  30. memset(iBuf, 0, sizeof(int) * 10);

  31. for (i = 0; i < 10; ++i)

  32. {

  33. printf("%d ", iBuf[i]);

  34. }

  35. printf("\n");


    上面的這些例子已經比較清楚地展示了memset函式的使用,當然,很常見的還有對結構體進行這樣的初始化操作,唯一的區別就是sizeof()的物件變成結構體即可,這裡大家可以自己嘗試。

 

    2. 需要注意的幾點

 

(1)memset中的第三個引數一定要使用sizeof操作符,因為每個系統下對型別長度的定義可能不一樣。

 

(2)memset中的第一個引數一定要是一個已知的、已經被分配記憶體的地址,否則會出錯。

 

(3)大家可能比較疑惑,memset的第一個引數已經有了被初始化空間的首地址,為什麼還要返回一個void*的指標去指向這個地址呢?這種結構在很多函式庫裡面比較常見,比如字串操作函式等,都有類似的現象,這裡之所以還要返回這個指標是為了實現鏈式程式設計,所謂鏈式程式設計,舉個例子大家就明白了。

 

 
  1. // 例4:鏈式程式設計

  2. int i = 0;

  3. char cBuf [10];

  4. char cBuf1[10];

  5.  
  6. // 這裡是關鍵!!!

  7. memcpy(cBuf1, memset(cBuf, 'a', sizeof(char) * 10), sizeof(char) * 10);

  8.  
  9. for (i = 0; i < 10; ++i)

  10. {

  11. printf("%c", cBuf[i]);

  12. }

  13. printf("\n");

  14.  
  15. for (i = 0; i < 10; ++i)

  16. {

  17. printf("%c", cBuf1[i]);

  18. }

  19. printf("\n");

 

    從上面這個例子中就可以看出,在memcpy這個函式中,直接使用了memset的返回值,用其來拷貝cBuf1這個字元陣列,這樣就可以直接連起來寫,看起來十分方便。但是這個例子的應用形式卻很少,只是為了說明這個問題才這樣寫的,具體的鏈式程式設計應用場合大家可以再仔細研究下,但是鏈式程式設計也使得程式碼變得有些不直觀,所以要有所取捨。

 

(4)最後一點,也是最重要的一點。一定要注意,memset是按照位元組對待初始化空間進行初始化的,也就是說,函式裡面的第二個引數的那個初值(一般為0)是按照一個一個位元組往第一個引數所指區域賦值的,所以,對於單位元組資料型別(char)可以初始化為任意支援的值,都沒有問題,但是對於非多位元組資料型別只能初始化為0,而不能初始化成別的初值,因為對所有位元組按任意順序賦值0的結果都是0,而如果初始化為其他的值,就會一個位元組一個位元組的進行賦值,從而出現奇怪的結果。比如說,上面的例3之所以沒有出錯就是因為初始化為0,但是如果初始化為1,那麼因為int一般是4個位元組,那麼相當於將一個int元素初始化成了0000 0001 0000 0001 0000 0001 0000 0001,這樣對於一個int元素肯定不是1,而是一個很大的數,結果出乎意料,所以一定要記住這一點,非常重要!!!