實作總結一下C常用庫中的一些函數,把書上的變成自己的!
其中:atoi 在标準庫,但itoa不在标準庫中, stdlib中,strcpy,strcmp,strlen,strcat,memcpy,memset 在庫string中
一 atoi
原型為 int atoi(const char *nptr),實作字元串轉為整型。 方法一:
int myatoi(const char *nptr)
{
assert(nptr != NULL);
int i = 0;
int sign = 1;
int number = 0;
while(' ' == nptr[i] || '\t'== nptr[i])
i++;
sign = (nptr[i] == '-') ? -1 : 1;
while('-' == nptr[i] || '+' == nptr[i])
i++;
while(nptr[i] != '\0')
{
number = number*10 + (nptr[i] - '0');
i++;
}
number = sign * number;
return number;
}
這種方法是網上常見的方法,但是在測試的過程中發現,當輸入字元串為“ -123 ”時,輸出結果不是-123,那時因為在最後一次循環中,隻判斷了是否為結束符,而沒有判斷是否不是數字,是以我做了如下修改:
while(nptr[i] >= '0' && nptr[i] <='9' )
{
number = number*10 + (nptr[i] - '0');
i++;
}
其效果等效于方法二中的 isdigit()函數。 方法二:可以直接調用ctype庫中的函數實作
int myatoi(const char *nptr)
{
assert(nptr != NULL);
int i = 0;
int sign = 1;
int number = 0;
while(isspace(nptr[i]))
i++;
sign = (nptr[i] == '-') ? -1 : 1;
while('-' == nptr[i] || '+' == nptr[i])
i++;
while(isdigit(nptr[i]))
{
number = number*10 + (nptr[i] - '0');
i++;
}
number = sign * number;
return number;
}
二 itoa
原型為 void itoa(int n, char [ ]),實作把整型轉為字元串。
由于整數長度未知,不能直接獲得整數,需要對其進行逆序。
void myitoa(const int num,char *s)
{
int n = num;
int i = 0;
int j = 0;
char *temp = new char[10];
if(n < 0)
{
s[i] = '-';
i++;
n = -num;
}
while(n > 0)
{
temp[j] = n%10 + '0';
n = n/10;
j++;
}
temp[j] = '\0';
j--;
while(j >=0)
s[i++] = temp[j--];
s[i] = '\0';
}
三 strcpy
原型為 char* strcpy(char *str1,const char * str2),把str2所指的字元串複制到str1中,傳回目的存儲區的初始位址
char* myStrcpy(char* dst,const char* src)
{
assert( src != NULL);
assert( dst != NULL);
char *address = dst;
// memcpy(dst,src,strlen(src)+1);
while((*dst++ = *src++) != '\0');
return address;
}
四 strcmp
原型為 int strcmp(const char *str1,const char * str2),比較str1,str2所指字元串的大小,如果str1 = str2,傳回0,str1 < str2,傳回<0,str1 > str2 ,傳回 >0。
int mystrcmp(const char *dst,const char *src)
{
assert(dst != NULL && src != NULL);
while(*dst && *src && *dst == *src)
{
dst++;
src++;
}
return *dst-*src;
}
五 strlen
原型為 int strlen(const char *str),傳回str的字元長度, 不包括'\0'(字元串中的空格包括在内)
int mystrlen(const char *src)
{
assert(src != NULL);
int length = 0;
while(*src != '\0')
{
length++;
src++;
}
return length;
}
六 strcat
原型為 char *strcat(char *str1,const char *str2),把str2所指的字元串連接配接到str1,并傳回目的存儲區初始位址
char *mystrcat(char *dst,const char *src)
{
assert(dst != NULL && src != NULL);
char *address = dst;
while(*dst != '\0')
dst++;
while((*dst ++ = *src ++) != '\0');
*dst = '\0';
return address;
}
注意:在dst指針移到dst末尾時,不能
while(*dst++ != '\0');
如果這樣的話,不能達到連接配接的效果,最後傳回的隻是dst的内容。這是因為* 和 ++ 的優先級一樣,則自左向右執行,即當判斷dst為結束符,其會指向下一個位元組,即'\0'的下一個位元組。是以address儲存的内容是:dst ‘\0’ src '\0',輸出時遇'\0'停止,即dst '\0'。
七 memcpy
原型為 void *memcpy(void *str,const void *str2,size_t n),存儲器拷貝,把str指的n個字元拷貝到str1中,傳回目的存儲區起始位址
void *mymemcpy(void *dst,const void *src,size_t n)
{
assert(dst != NULL && src != NULL);
//assert((dst >= src+n) || (src >dst+n));
char *tempdst =(char *) dst;
char *tempsrc = (char *)src;
while(n-- )
*tempdst++ = *tempsrc++;
return dst;
}
為了防止記憶體重疊,可以做如下修改:
void *mymemcpy(void *dst,const void *src,size_t n)
{
assert(dst != NULL && src != NULL);
char *tempdst =(char *) dst;
char *tempsrc = (char *)src;
//assert((tempdst >= tempsrc+n) || (tempsrc > tempdst+n));
size_t i = 0;
if(tempdst > tempsrc && tempdst < tempsrc + n)
{
while(n--)
*tempdst++ = *tempsrc++;
}
else
{
while(n--)
*tempdst++ = *tempsrc++;
}
return dst;
}
int _tmain(int argc, _TCHAR* argv[])
{
char src[] = "abadc";
char dst[] = "SCH";
mymemcpy(dst,src,2*sizeof(char));
cout <<dst<<endl;
return 0;
}
注意:函數調用時,傳回值隻是位址。
memcpy和strcpy差別: 1.strcpy隻能複制字元串,而memcpy不限制資料類型 2.strcpy不需要知道字元串長度,一直複制,直到'\0',這樣容易溢出,而memcpy遇到'\0'不停止,指導n才結束。
八 memset
原型為 void *memset(void *str,int v,size_t n),把str所指區域的前n個位元組均設為v,傳回的是該區域的起始位址。
void *mymemset(void *dst,int v,size_t n)
{
assert(dst != NULL);
char *address = (char *)dst;
while(n--)
*address++ = v;
return dst;
}
對于memset來說,沒有越界不越界之分,數組的界是程式員邏輯一部分,memset不管,是以如果在超出數組上限時,超出記憶體都沒有被其他程序所占用,那麼一切正常。但是如果有至少一個位元組的記憶體區域屬于其他程序,那麼我這個程式将會出現運作時錯誤。