C常用字串函式模擬、記憶體重疊問題
當我們在模擬字串函式的時候需要注意兩點:
■ 檢查引數合法性
■ 對指標進行引數保護
字串長度strlen
注意點:
字串以 ‘\0’ 作為結束標志,strlen函式回傳的是在字串中 ‘\0’ 前面出現的字符個數(不包含 ‘\0’ ),引數指向的字串必須要以 ‘\0’ 結束,注意函式的回傳值為size_t,是無符號的(易錯),
//注意回傳值是size_t
size_t my_strlen(const char *string) {
assert(string!=NULL); //1.檢查引數合法性
const char* src = string; //2.對指標進行引數保護
size_t len = 0; //長度需要和回傳值對應
while (*src++ != '\0') {
len++;
}
return len;
}
長度不受限制的字串函式
strcpy
注意點:
源字串必須以 ‘\0’ 結束,會將源字串中的 ‘\0’ 拷貝到目標空間,目標空間必須足夠大,以確保能存放源字串,目標空間必須可變,
char* my_strcpy(char* strDest, const char* strSrc)
{
assert(strDest != NULL && strSrc != NULL); //1檢查引數合法性
char* pDest = strDest;
const char* pSrc = strSrc; //2 保護引數
while (*pDest++ = *pSrc++); //先將*pSrc的值賦給*pDest,然后判斷pSrc的值是不是'\0'然后pSrc++,pDest++;
//當然也可以這樣寫
/*
while(*pSrc!='\0'){
*pDest=*pSrc;
pDest++;
pSrc++;
}
*pDest='\0';
*/
return strDest;
}
strcat
提示:src和dest所指記憶體區域不可以重疊且dest必須有足夠的空間來容納src的字串,
char* my_strcat(char* strDest, const char* strSrc)
{
assert(strDest!=NULL&&strSrc!=NULL);//1.檢查引數的合法性
char* pDest = strDest; //2.對引數指標進行保護
const char* pSrc = strSrc;
//先找到strSrc的'\0'的位置
while (*pDest !='\0') {
pDest++;
}
//實行連接拷貝
while (*pSrc!='\0') {
*pDest++ = *pSrc++;
}
//增加結束標記
*pDest = '\0';
return strDest;
}
strcmp
//string1>string2 回傳值大于0
//string1=string2 回傳值等于0
//string1<string2 回傳值小于0
int my_strcmp(const char* string1, const char* string2)
{
assert(string1!=NULL&&string2!=NULL); //1.引數合法性檢查
const char* ps1 = string1; //2.指標進行引數保護
const char* ps2 = string2;
while (*ps1!='\0'||*ps2!='\0') { //當存在兩個字串沒有同時到達末尾就回圈 當同時到達末尾時,res=0即字串相等
if (*ps1 - *ps2 != 0) //當存在兩個字符不相等時就跳出回圈,即使有一個字串達到字串末尾,我們在(*ps1-*ps2)進行統一判斷,
break;
ps1++;
ps2++;
}
int res = *ps1 - *ps2;
return res;
}
長度受限制的字串函式
函式原型通過添加count值來限制所能操作字串的長度,
strncpy
char* my_strncpy(char* strDest, const char* strSrc,size_t count)
{
assert(strDest != NULL && strSrc != NULL); //1檢查引數
char* pDest = strDest;
const char* pSrc = strSrc; //2 保護引數
while (count--) {
*pDest++ = *pSrc++;
}
return strDest;
}
strncat
說 明:src和dest所指記憶體區域不可以重疊且dest必須有足夠的空間來容納src的字串,
char* my_strncat(char* strDest, const char* strSrc, size_t count)
{
assert(strDest!=NULL&&strSrc!=NULL);
char* pDest = strDest;
const char* pSrc = strSrc;
while (*pDest !='\0') {
pDest++;
}
while (count--) {
*pDest++ = *pSrc++;
}
*pDest = '\0';
return strDest;
}
strncmp
int my_strncmp(const char* string1, const char* string2,size_t count)
{
assert(string1 != NULL && string2 != NULL); //1.引數合法性檢查
const char* ps1 = string1; //2.指標進行引數保護
const char* ps2 = string2;
while (--count) { //要先減了再判斷是不是>0,因為ps1++,ps2++會提前到達下一個字符
if (*ps1 - *ps2 != 0) //當存在兩個字符不相等時就跳出回圈,即使有一個字串達到字串末尾,我們在(*ps1-*ps2)進行統一判斷,
break;
ps1++;
ps2++;
}
int res = *ps1 - *ps2;
return res;
}
記憶體操作函式
就是說這個標準規定memcpy是不處理的,但是基于編譯器 可能會處理也可能不會處理,但是對于memmove這個標準規定是一定會處理的
memcpy
■ 函式memcpy從src的位置開始向后復制num個位元組的資料到des的記憶體位置,以位元組為單位進行復制,
■ 這個函式在遇到 ‘\0’ 的時候并不會停下來,
■ 如果source和destination有任何的重疊,復制的結果都是未定義的,
void* my_memcpy(void* dest, const void* src, size_t count) {
assert(dest&&src); //檢查引數合法性
char* pdest = (char *)dest;//指標進行引數保護
const char* psrc = (const char*)src;
while (count--) {
*pdest++ = *psrc++;
}
return dest;
}
memmove
■ 和memcpy的差別就是memmove函式處理的源記憶體塊和目標記憶體塊是可以重疊的,
■ 如果源空間和目標空間出現重疊,就得使用memmove函式處理,
記憶體重疊:拷貝的目的地址在源地址范圍內,所謂記憶體重疊就是拷貝的目的地址和源地址有重疊,
原型:void* my_memmove(void* dest, const void* src, size_t count);

解決辦法:
■ 判斷是否記憶體重疊,記憶體重疊從后往前復制,
■ 沒有記憶體重疊,從前往后復制,
void* my_memmove(void* dest, const void* src, size_t count) {
assert(dest&&src);
char* pdest = (char *)dest;
const char* psrc = (const char*)src;
if (pdest>psrc&&pdest<psrc+count) { //判斷有記憶體重疊
pdest = pdest + count - 1; //從后往前賦值
psrc = psrc + count - 1;
while (count--) {
*pdest-- = *psrc--;
}
}
else { //沒有記憶體重疊的情況
while (count--) {
*pdest++ = *psrc++;
}
}
return dest;
}
memmove和memcpy的唯一區別:在C語言標準中規定當記憶體發生區域重疊的時候,memmove保證拷貝的結果是正確的,memcpy不保證拷貝的結果的正確,memcpy只是不保證結果的正確性,但是結果也有可能是正確的,這取決于自己的編譯器,有一些編譯器memcpy函式也是處理了記憶體區域重疊的情況,
測驗情況:

memcmp
int my_memcmp(const void* buf1, const void* buf2, size_t count)
{
assert(buf1&&buf2);
const char* pbuf1 = (const char*)buf1;
const char* pbuf2 = (const char*)buf2;
while (count--) {
if (*pbuf1 - *pbuf2 != 0)
break;
pbuf1++;
pbuf2++;
}
return (*pbuf1-*pbuf2);
}
memset
void* my_memset(void* dest, int c, size_t count)
{
assert(dest);
char* pdest = (char*)dest;
while (count--) {
*pdest++ = c;
}
return dest;
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/228109.html
標籤:其他
上一篇:2020-11-10
