前言:
我們之前學過strcpy,strcmp等等函數,他們可以拷貝字符串和比較字符串等等,那么有沒有什么函數不光可以拷貝字符串還可以拷貝其他的數據呢,答案就是內存函數。
相較于字符串函數,內存函數可以拷貝的數據類型不受限制,故名思意,內存函數就是直接操作內存塊的,因此任何類型的數據都可以進行操作,那么接下來我們需要學習的內存函數有memcpy,memmove,memset,memcmp。
memcpy
memcpy函數是一個內存拷貝函數,它可以將一塊內存的數據拷貝給另一塊內存,以下是它的函數原型:?
?該函數存在三個參數:
- dest:指向目標內存,簡單說就是我們需要拷貝的數據存放的對象,比如我們像把數組1的數據拷貝給數組2,那么數組2就是拷貝的目標
- src:指向拷貝的來源,就是我們數據拷貝的來源,借用上面的例子就是數組1
- num:需要我們傳入拷貝的內存大小,以字節為單位,比如說我們要拷貝一個int類型,那么num就需要傳入4,或者sizeof(int)。
函數使用代碼展現:?
// 內存函數
// memcpy
int main()
{// 來源數組1int arr1[] = { 0,1,2,3,4,5,6,7,8,9,10 };// 目標數組2int arr2[20] = { 0 };// 拷貝memcpy(arr2, arr1, 11 * sizeof(int));// 打印for (int i = 0; i < 20; i++){printf("%d ", arr2[i]);}return 0;
}
運行結果:?
這邊注意我們拷貝的目標數組的容量一定要大于或者等于拷貝數據的大小,否則會出現錯誤。
?了解了使用方法后,讓我們來自己實現這個函數的功能把。
函數分析:?
?通過函數模型知道我們也需要dst,src指針指向目標和來源,num傳入拷貝的大小(以字節為單位)。
void* my_memcpy(void* dst, const void* src, size_t num)
{void* ret = dst;while (num--){*(char*)dst = *(char*)src; // 用char*進行強轉保障每次的拷貝是一個字節// 建議寫法1,不可以直接++// 寫法1/*dst = (char*)dst + 1;src = (char*)src + 1;*/// 寫法2((char*)dst)++;((char*)src)++;}return ret;
}
?memmove
memmove函數的使用方法和功能和memcpy基本一致,唯一有區別的是,如果按照我們上面實現memcpy函數的方法,我們是無法實現內存重疊的拷貝的,什么是內存重疊呢,我們來看下面一段代碼:?
int main()
{int arr[] = { 1,2,3,4,5,6,7,8,9,10 };my_memcpy(arr+2, arr, 5 * sizeof(int));for (int i = 0; i < 10; i++){printf("%d ", arr[i]);}return 0;
}
?我們自己拷貝給自己,arr代表數組首元素地址,arr+2指向的就是3,我們需要將1,2,3,4,5,從3的位置拷貝上去。
?最后的拷貝如上圖,但是實際我們運行時如下圖。
?因為拷貝的時候都是從頭到尾,會發生覆蓋問題,為了解決這樣內存塊重疊拷貝的問題,推出了memmove函數,當然現在在VS上的memcpy也可以解決這樣的問題,但是涉及內存塊重疊拷貝還是建議使用memmove函數。
函數原型:?
?該函數存在三個參數:
- dest:指向目標內存,簡單說就是我們需要拷貝的數據存放的對象,比如我們像把數組1的數據拷貝給數組2,那么數組2就是拷貝的目標
- src:指向拷貝的來源,就是我們數據拷貝的來源,借用上面的例子就是數組1
- num:需要我們傳入拷貝的內存大小,以字節為單位,比如說我們要拷貝一個int類型,那么num就需要傳入4,或者sizeof(int)。
?函數使用代碼展現:
int main()
{int arr[] = { 1,2,3,4,5,6,7,8,9,10 };memmove(arr + 2, arr, 5 * sizeof(int));for (int i = 0; i < 10; i++){printf("%d ", arr[i]);}return 0;
}
?運行結果:?
?代碼實現:
void* my_memmove(void* dst, const void* src, size_t num)
{void* ret = dst;if (dst < src){//前->后while (num--){*(char*)dst = *(char*)src;dst = (char*)dst + 1;src = (char*)src + 1;}}else{// 后->前while (num--){*((char*)dst + num) = *((char*)src + num);}}return ret;
}int main()
{int arr[] = { 1,2,3,4,5,6,7,8,9,10 };my_memmove(arr+4, arr+2, 5 * sizeof(int));for (int i = 0; i < 10; i++){printf("%d ", arr[i]);}return 0;
}
?memset
?memset是?來設置內存的,將內存中的值以字節為單位設置成想要的內容。
int main ()
{
char str[] = "hello world";
memset (str,'x',6);
printf(str);
return 0;
}
?因為是以每一個字節取設置內存,對于其他存儲高于一個字節的類型只能初始化,不可以設置其他的值,會產生錯誤:
int main()
{int arr[10];memset(arr, 0, 10*sizeof(int));for (int i = 0; i < 10; i++){printf("%d ", arr[i]);}return 0;
}
int main()
{int arr[10];memset(arr, 1, 10*sizeof(int));for (int i = 0; i < 10; i++){printf("%d ", arr[i]);}return 0;
}
?
memcmp?
?較從ptr1和ptr2指針指向的位置開始,向后的num個字節,內存函數的比較也是一個字節一個字節的比較。
函數原型:
#include <stdio.h>
#include <string.h>
int main()
{
char buffer1[] = "DWgaOtP12df0";
char buffer2[] = "DWGAOTP12DF0";
int n;
n = memcmp(buffer1, buffer2, sizeof(buffer1));
if (n > 0)
printf("'%s' is greater than '%s'.\n", buffer1, buffer2);
else if (n < 0)
printf("'%s' is less than '%s'.\n", buffer1, buffer2);
else
printf("'%s' is the same as '%s'.\n", buffer1, buffer2);
return 0;
}