內存操作函數memmove,memcpy,memset
通過字符串的學習,我們知道字符串操作函數的操作對象是字符串,並且它的結束標誌是結束符\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- #define _CRT_SECURE_NO_WARNINGS 1
- #include<stdio.h>
- #include<assert.h>
- voidvoid *my_memcpy(voidvoid *dest, const voidvoid *src, size_t size)
- {
- assert(dest);
- assert(src);
- charchar *str1 = (charchar *)dest;
- const charchar *str2 = (const charchar *)src;
- while (size)
- {
- *str1 = *str2;
- str1++;
- str2++;
- size--;
- }
- return dest;
- }
- int main()
- {
- char arr[] = "hel love you";
- voidvoid *ret = my_memcpy(arr,"ylrr",3);
- charchar *p = (charchar *)ret;
- printf("%s",p);
- system("pause");
- return 0;
- }
代碼分析:函數的參數有三個,兩個為void型指針,最後一個是整形變量,表示拷貝內存的字節數。
為什麽要寫成void型指針呢?主要是為了可以接收各種類型的指針,因為我們有時想拷貝的區域是存放整 形數的,有時想拷貝的區域是存放字符串的,我們總不能根據內存區域數據的類型經常改函數參數吧,這 樣得有多麻煩呀~~所以用void*就比較好~~
函數的返回值是void*類型,這一點類似上邊的參數。
另外需要註意的是,void型的指針不能進行自加操作,也不能進行解引用,所以函數中都進行了強制類型 轉化。因為操作過程中是一個字節一個字節進行,所以強制轉化成char *。比如:
void *p;
p++;//錯誤
*p = 1;//錯誤
下邊我們來模擬實現memmove函數:
首先來分析memmove實現拷貝的幾種情況:如下圖
從圖中我們可以看出,當dest>src && dest < src+size,我們需要從後向前拷貝,其他情況從前向後拷貝。
代碼如下:
[objc] view plain copy- #define _CRT_SECURE_NO_WARNINGS 1
- #include<stdio.h>
- #include<assert.h>
- <pre name="code" class="objc">void* my_memmove(voidvoid *dest, const voidvoid *src, size_t size)
- {
- assert(dest);
- assert(src);
- charchar *str1 = (charchar *)dest;
- const charchar *str2 = (const charchar *)src;
- if ((str2 > str1) && (str2< str1 + size))
- {
- while (size)
- {
- *str1 = *str2;
- str1++;
- str2++;
- size--;
- }
- }
- else
- {
- while (size--)
- {
- *(str1 + size) = *(str2 + size);
- }
- }
- return dest;
- }
- int main()
- {
- char arr[] = "abcdef";
- voidvoid *ret = my_memmove(arr+2,arr,4);
- printf("%s",arr);
- system("pause");
- return 0;
- }
代碼分析:代碼中所給出的測試案例是從後向前拷貝,程序運行結果是ababcd,在程序輸出時,不能輸出返回的值, 因為一般情況那都是不對的,具體原因其實很簡單。
從前向後拷貝比較簡單,直接賦值,然後自加;從後向前拷貝時,第一次復制時,目標串和原串均向後偏移size-1,在程序代碼中,當進行while循環條件判斷時, size自減,所以到循環體內,size已經減了1.所以,你看到的是偏移size。
memset函數:
函數原型:void* memset(void *dest,int c,size_t size);給出內存的起始地址,將從起始地址開始的size個字節
賦值為字符c。這個函數實現起來比較簡單。
[objc] view plain copy- voidvoid * my_memset(voidvoid *dest, int c, size_t size)
- {
- assert(dest);
- charchar *pdest = (charchar *)dest;
- while (size--)
- {
- *pdest++ = c;
- }
- return dest;
- }
- int main()
- {
- char arr[] = "abcdef";
- my_memset(arr,‘0‘,3);
- printf("%s",arr);
- system("pause");
- return 0;
- }
註:函數中給出的字符是整形,這個賦值的時候不用強制類型轉換,因為字符變量在內存中就是以其ascii形式存儲~~
內存操作函數memmove,memcpy,memset