1. 程式人生 > >內存操作函數memmove,memcpy,memset

內存操作函數memmove,memcpy,memset

ems print 其他 pbo number 一次 csdn cde con

通過字符串的學習,我們知道字符串操作函數的操作對象是字符串,並且它的結束標誌是結束符\0,當然這個說的是不

受限制的字符串函數。然而當我們想要將一段內存的數據復制到另一塊內存時,我們不能使用字符串操作函數,當然也

不能一個一個復制,所以就引入了內存操作函數。

memcpy函數原型:

void *memcpy(void *dst, const void *src, size_t size);將一塊內存的數據復制到另一塊內存。當兩塊內存重疊 的時候,memcpy就不能保證拷貝正確。

memmove函數原型:

void *memmove(void *dst, const void *src, size_t size); 可以拷貝內存重疊的,也可以拷貝不重疊的。

下面模擬實現memcpy函數:

[objc] view plain copy
  1. #define _CRT_SECURE_NO_WARNINGS 1
  2. #include<stdio.h>
  3. #include<assert.h>
  4. voidvoid *my_memcpy(voidvoid *dest, const voidvoid *src, size_t size)
  5. {
  6. assert(dest);
  7. assert(src);
  8. charchar *str1 = (charchar *)dest;
  9. const charchar *str2 = (const charchar *)src;
  10. while (size)
  11. {
  12. *str1 = *str2;
  13. str1++;
  14. str2++;
  15. size--;
  16. }
  17. return dest;
  18. }
  19. int main()
  20. {
  21. char arr[] = "hel love you";
  22. voidvoid *ret = my_memcpy(arr,"ylrr",3);
  23. charchar *p = (charchar *)ret;
  24. printf("%s",p);
  25. system("pause");
  26. return 0;
  27. }

代碼分析:函數的參數有三個,兩個為void型指針,最後一個是整形變量,表示拷貝內存的字節數。

為什麽要寫成void型指針呢?主要是為了可以接收各種類型的指針,因為我們有時想拷貝的區域是存放整 形數的,有時想拷貝的區域是存放字符串的,我們總不能根據內存區域數據的類型經常改函數參數吧,這 樣得有多麻煩呀~~所以用void*就比較好~~

函數的返回值是void*類型,這一點類似上邊的參數。

另外需要註意的是,void型的指針不能進行自加操作,也不能進行解引用,所以函數中都進行了強制類型 轉化。因為操作過程中是一個字節一個字節進行,所以強制轉化成char *。比如:

void *p;

p++;//錯誤

*p = 1;//錯誤

下邊我們來模擬實現memmove函數:

首先來分析memmove實現拷貝的幾種情況:如下圖技術分享

從圖中我們可以看出,當dest>src && dest < src+size,我們需要從後向前拷貝,其他情況從前向後拷貝。

代碼如下:

[objc] view plain copy
  1. #define _CRT_SECURE_NO_WARNINGS 1
  2. #include<stdio.h>
  3. #include<assert.h>
  4. <pre name="code" class="objc">void* my_memmove(voidvoid *dest, const voidvoid *src, size_t size)
  5. {
  6. assert(dest);
  7. assert(src);
  8. charchar *str1 = (charchar *)dest;
  9. const charchar *str2 = (const charchar *)src;
  10. if ((str2 > str1) && (str2< str1 + size))
  11. {
  12. while (size)
  13. {
  14. *str1 = *str2;
  15. str1++;
  16. str2++;
  17. size--;
  18. }
  19. }
  20. else
  21. {
  22. while (size--)
  23. {
  24. *(str1 + size) = *(str2 + size);
  25. }
  26. }
  27. return dest;
  28. }
  29. int main()
  30. {
  31. char arr[] = "abcdef";
  32. voidvoid *ret = my_memmove(arr+2,arr,4);
  33. printf("%s",arr);
  34. system("pause");
  35. return 0;
  36. }




代碼分析:代碼中所給出的測試案例是從後向前拷貝,程序運行結果是ababcd,在程序輸出時,不能輸出返回的值, 因為一般情況那都是不對的,具體原因其實很簡單。

從前向後拷貝比較簡單,直接賦值,然後自加;從後向前拷貝時,第一次復制時,目標串和原串均向後偏移size-1,在程序代碼中,當進行while循環條件判斷時, size自減,所以到循環體內,size已經減了1.所以,你看到的是偏移size。

memset函數:

函數原型:void* memset(void *dest,int c,size_t size);給出內存的起始地址,將從起始地址開始的size個字節

賦值為字符c。這個函數實現起來比較簡單。

[objc] view plain copy
  1. voidvoid * my_memset(voidvoid *dest, int c, size_t size)
  2. {
  3. assert(dest);
  4. charchar *pdest = (charchar *)dest;
  5. while (size--)
  6. {
  7. *pdest++ = c;
  8. }
  9. return dest;
  10. }
  11. int main()
  12. {
  13. char arr[] = "abcdef";
  14. my_memset(arr,‘0‘,3);
  15. printf("%s",arr);
  16. system("pause");
  17. return 0;
  18. }

註:函數中給出的字符是整形,這個賦值的時候不用強制類型轉換,因為字符變量在內存中就是以其ascii形式存儲~~

內存操作函數memmove,memcpy,memset