網(wǎng)站開發(fā)包含哪些網(wǎng)站下載
? ? ? ?? ??歡迎大家來到貝蒂大講堂??
? ? ? ??????🎈🎈養(yǎng)成好習(xí)慣,先贊后看哦~🎈🎈
? ? ? ? ? ? ? ? ?所屬專欄:C語言學(xué)習(xí)? ? ? ??
? ? ? ? ? ? ? ? ?貝蒂的主頁:Betty‘s blog
目錄
?1. 簡介
?2. memset()函數(shù)
? ?2.1用法
2.2實例
2.3 實現(xiàn)memset()?
3.? memcmp()函數(shù)
3.1用法
?3.2 實例
3.3 實現(xiàn)memcmp()?
3.4strcmp,strncmp,memcmp之間的區(qū)別?
4. memcpy()函數(shù)?
4.1用法
?4.2 實例
4.3實現(xiàn)memcpy()?
4.4strcpy,strncpy,memcpy之間的區(qū)別
5. memmove()函數(shù)
5.1用法
?5.2實例
5.3實現(xiàn)memmove()
?1. 簡介
? ? ?除了字符函數(shù)和字符串函數(shù),<string.h>中還有一類內(nèi)存操作函數(shù),如memset(),memcmp()等函數(shù),他們在功能和某些字符串函數(shù)很像,但作用范圍更廣,除了作用于字符串外,還可以作用于int ,double等類型,但因為是以字節(jié)為單位改變,所以限制也很大。下面就讓我們來看看吧~
?2. memset()函數(shù)
? ?2.1用法
1. 聲明:void *memset(void *str, int c, size_t n)
- str?-- 指向要填充的內(nèi)存塊。
- c?-- 要被設(shè)置的值。該值以 int 形式傳遞,但是函數(shù)在填充內(nèi)存塊時是使用該值的無符號字符形式。
- n?-- 要被設(shè)置為該值的字符數(shù)。
2.?復(fù)制字符?c(一個無符號字符)到參數(shù)?str?所指向的字符串的前?n?個字符。
3. 返回值:該值返回一個指向存儲區(qū) str 的指針。
2.2實例
#include <stdio.h>
#include <string.h>
int main()
{char str[] = "hello world";memset(str, 'x', 6);//以字節(jié)為單位printf(str);return 0;
}
輸出結(jié)果:xxxxxxworld?
int main()
{int arr[4] = { 1,2,3,4 };memset(arr, 1, sizeof(arr));int i = 0;for (i = 0; i < 4; i++){printf("%d ", arr[i]);}return 0;
}
?輸出結(jié)果:16843009 16843009 16843009 16843009
貝蒂說:“雖然memset可以作用于int,float等類型,但是memset設(shè)置是以字節(jié)為單位,容易造成不符合我們預(yù)期的情況哦~”
2.3 實現(xiàn)memset()?
思路:memset()函數(shù)和strcpy()函數(shù)有點(diǎn)像,都是替換,但是內(nèi)在實現(xiàn)也有區(qū)別,因為memset()函數(shù)還可以用于不同數(shù)據(jù)類型,所以要先強(qiáng)制類型為(char*),再以字節(jié)為單位替換。
代碼實現(xiàn):
#include <string.h>
#include<assert.h>
void* my_memset(void*str, int c, size_t n)
{assert(str);//防止str為空指針char* tmp= (char*)str;//以字節(jié)為單位改變while (n--){*tmp = c;tmp++;}return str;
}
int main()
{char str[] = "hello world";my_memset(str, 'x', 6);//以字節(jié)為單位printf(str);return 0;
}
貝蒂說:“memset()函數(shù)常用于初始化哦~”?
3.? memcmp()函數(shù)
3.1用法
1. 聲明:int memcmp(const void *str1, const void *str2, size_t n)
- str1?-- 指向內(nèi)存塊的指針。
- str2?-- 指向內(nèi)存塊的指針。
- n?-- 要被比較的字節(jié)數(shù)。
2. 作用:把存儲區(qū)?str1?和存儲區(qū)?str2?的前?n?個字節(jié)進(jìn)行比較。
3. 返回值:
- 如果返回值 < 0,則表示 str1 小于 str2。
- 如果返回值 > 0,則表示 str1 大于 str2。
- 如果返回值 = 0,則表示 str1 等于 str2。
?3.2 實例
#include <stdio.h>
#include <string.h>
int main()
{char str1[] = "Hello, World!";char str2[] = "Hello, World!";char str3[] = "Hello, Betty!";// 比較相同的字符串if (memcmp(str1, str2, strlen(str1)) == 0){printf("str1 和 str2 相同。\n");}// 比較不同的字符串if (memcmp(str1, str3, strlen(str1)) != 0) {printf("str1 和 str3 不同。\n");}return 0;
}
?輸出:
str1 和 str2 相同。
str1 和 str3 不同。
3.3 實現(xiàn)memcmp()?
思路:總體思路與strncmp差不多,只是也需要先強(qiáng)制類型轉(zhuǎn)換
#include<stdio.h>
#include<assert.h>
int my_memcmp(const void* str1, const void* str2, size_t n)
{assert(str1 && str2);//char* p1 = (char*)str1;char* p2 = (char*)str2;while (n--&&(*p1==*p2)){if (*p1 == '\0'){return 0;}p1++;p2++;}return *p1 - *p2;
}
貝蒂說:“memcmp()函數(shù)也是以字節(jié)比較,所以限制也很大哦~”?
3.4strcmp,strncmp,memcmp之間的區(qū)別?
- memcmp是比較兩個存儲空間的前n個字節(jié),即使字符串已經(jīng)結(jié)束,仍然要比較剩余的空間,直到比較完n個字節(jié)。
- strcmp比較的是兩個字符串,任一字符串結(jié)束,則比較結(jié)束。
- strncmp在strcmp的基礎(chǔ)上增加比較個數(shù),其結(jié)束條件包括任一字符串結(jié)束和比較完n個字節(jié)。
- strcmp比較的字符串,而memcmp比較的是內(nèi)存塊,strcmp需要時刻檢查是否遇到了字符串結(jié)束的 /0 字符,而memcmp則完全不用擔(dān)心這個問題,所以memcmp的效率要高于strcmp
4. memcpy()函數(shù)?
4.1用法
1. 聲明:void *memcpy(void *str1, const void *str2, size_t n)
- str1?-- 指向用于存儲復(fù)制內(nèi)容的目標(biāo)數(shù)組,類型強(qiáng)制轉(zhuǎn)換為 void* 指針。
- str2?-- 指向要復(fù)制的數(shù)據(jù)源,類型強(qiáng)制轉(zhuǎn)換為 void* 指針。
- n?-- 要被復(fù)制的字節(jié)數(shù)。
2. 作用:從存儲區(qū)?str2?復(fù)制?n?個字節(jié)到存儲區(qū)?str1。
3. 返回值:該函數(shù)返回一個指向目標(biāo)存儲區(qū) str1 的指針。
?4.2 實例
int main()
{int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };int arr2[10] = { 0 };memcpy(arr2, arr1, 20);//前五個元素int i = 0;for (i = 0; i < 10; i++){printf("%d ", arr2[i]);}return 0;
}
輸出結(jié)果:1 2 3 4 5 0 0 0 0 0?
4.3實現(xiàn)memcpy()?
思路:自然也是和strcpy()差不多啦,嘻嘻
void* my_memcpy(void* dest, const void* src, size_t n)
{assert(dest && src);//防止空指針void* ret = dest;while (n--){*(char*)dest = *(char*)src;dest = (char*)dest + 1;src = (char*)src + 1;}return ret;
}
貝蒂說:“因為memcpy()函數(shù)實現(xiàn)機(jī)制,所以不能自己對自己進(jìn)行拷貝哦~”?
4.4strcpy,strncpy,memcpy之間的區(qū)別
- memcpy是從源存儲空間拷貝到目標(biāo)存儲空間;而strcpy,strncpy是從源字符串拷貝到目標(biāo)字符串。
- memcpy拷貝時是按照參數(shù)n作為結(jié)束標(biāo)志的,即拷貝n個字節(jié)就結(jié)束;strncpy是以參數(shù)n或者‘\0’為結(jié)束標(biāo)志;strcpy是判斷‘\0’為結(jié)束標(biāo)志。
5. memmove()函數(shù)
5.1用法
? ? 我們上面說過memcpy()無法對自己進(jìn)行拷貝,那有沒有能對自己拷貝的函數(shù)呢,當(dāng)然有啦,就是我們的memmove()函數(shù)。
1. 聲明:void *memmove(void *str1, const void *str2, size_t n)
- str1?-- 指向用于存儲復(fù)制內(nèi)容的目標(biāo)數(shù)組,類型強(qiáng)制轉(zhuǎn)換為 void* 指針。
- str2?-- 指向要復(fù)制的數(shù)據(jù)源,類型強(qiáng)制轉(zhuǎn)換為 void* 指針。
- n?-- 要被復(fù)制的字節(jié)數(shù)。
2. 作用:從?str2?復(fù)制?n?個字符到?str1,但是在重疊內(nèi)存塊這方面,memmove() 是比 memcpy() 更安全的方法。如果目標(biāo)區(qū)域和源區(qū)域有重疊的話,memmove() 能夠保證源串在被覆蓋之前將重疊區(qū)域的字節(jié)拷貝到目標(biāo)區(qū)域中,復(fù)制后源區(qū)域的內(nèi)容會被更改。如果目標(biāo)區(qū)域與源區(qū)域沒有重疊,則和 memcpy() 函數(shù)功能相同。
3. 返回值:該函數(shù)返回一個指向目標(biāo)存儲區(qū) str1 的指針。
?5.2實例
#include <stdio.h>
#include <string.h>
int main()
{char str[] = "Hello, World!";printf("Original string: %s\n", str);// 將字符串前6個字符移動到字符串的末尾memmove(str, str + 7, 6);printf("Modified string: %s\n", str);return 0;
}
輸出結(jié)果:
Original string: Hello, World!
Modified string: World! World!
5.3實現(xiàn)memmove()
?分析如下:
? 情況1:
//假設(shè)需要拷貝以下場景
int arr1[9] = { 1,2,3,4,5,6,7,8,9 };
my_memmove(arr1, arr1 + 2, 12);
?
? 1. 假設(shè)我們從3的位置開始拷貝,3-1,4-2,5-3,拷貝成功。
? 2. 假設(shè)我們從5的位置開始拷貝,5-3,4-2,5-1,拷貝失敗。
?情況2:?
//假設(shè)我們要拷貝的情況如下
int arr1[9] = { 1,2,3,4,5,6,7,8,9 };
my_memmove(arr1+4, arr1 + 2, 12);
?
?1. 假設(shè)我們從3的位置開始拷貝,3-5,4-6,3-7,拷貝失敗。
?2. 如果我們從5的位置開始拷貝,:5-7,4-6,3-5,拷貝成功。
?情況3:?
int arr1[9] = { 1,2,3,4,5,6,7,8,9 };
my_memmove(arr1+1, arr1 + 5, 12);
my_memmove(arr1 + 5, arr1 + 1, 12);
?
1. 假設(shè)從6開始拷貝,6-2,7-3,8-4,拷貝成功。
2. 假設(shè)從8開始拷貝,8-4,7-3,6-2,拷貝成功。
?
1. 假設(shè)從2開始拷貝,2-6,3-7,4-9,拷貝成功。
2. 假設(shè)從4開始拷貝,4-8,3-7,2-6,拷貝成功。
總結(jié):如果dest字符串在src的字符左邊,則從首元素拷貝。如果dest字符串在src右邊,則從末尾元素開始拷貝。
代碼實現(xiàn):
void* my_memmove(void* dest, const void* src, size_t n)
{assert(dest && src);//防止空指針void* ret = dest;if (dest <= src)//dest在src左側(cè){while (n--){*(char*)dest = *(char*)src;dest = (char*)dest + 1;src = (char*)src + 1;}}else//dest在src的右側(cè){dest = (char*)dest + n - 1;//指向末尾src = (char*)src + n - 1;//指向末尾while (n--){*(char*)dest = *(char*)src;dest = (char*)dest - 1;src = (char*)src - 1;}}return ret;
}
? ? ? ? ?🎈🎈完結(jié)撒花🎈🎈
? ? ? ? ?🎈🎈完結(jié)撒花🎈🎈