幾個常見字串處理函式的實現原理
字串是一種常見的資料結構,對字串的處理又可以十分靈活,所以在實際開發,尤其是非數值處理中,字串的應用非常廣泛。雖然很多字串操作都封裝在了函式庫裡,應用程式可以直接通過呼叫庫函式來實現字串處理,然而對於開發者而言,若能瞭解其底層實現原理,對於應用程式設計而言還是大有裨益的。
這篇文章主要介紹幾種常用的字串處理函式的實現原理。
一、strlen函式
strlen函式:計算字串的實際長度,不包括’\0’。
演算法:從第一個字元開始掃描,直到遇見第一個’\0’,停止掃描,返回字串長度。
程式碼如下:
int strlen(const char *str) { int n=0; assert(str!=NULL); while(*str++!='\0') ++n; return n; }
二、strcat函式
strcat函式:將源字串str2新增到目的字串str1的末尾,同時覆蓋str1末尾的’\0’,並在新的str1末尾新增’\0’,返回指向str1的指標。
演算法:掃描str1,直到遇見’\0’,將str2逐個字元新增到str1末尾,最後新增’\0’。
程式碼如下:
char *strcat(char *str1, const char *str2) { char *p=str1; assert( (str1!=NULL) && (str2!=NULL) ); while(*str1!='\0') str1++; while(*str1++=*str2++); return p; }
三、strcmp函式
strcmp函式:比較str1和str2兩個字串的大小,若str1>str2,則返回正數;若str1<str2,則返回負數;若str1==str2,則返回0。
演算法:逐個比較str1和str2的每個字元,若相等且未遇見’\0’,則繼續比較下一個字元,否則,返回*str1和*str2的差值。
程式碼如下:
int strcmp(const char *str1, const char *str2) { assert( (str1!=NULL) && (str2!=NULL) ); while(*str1 && *str2&& (*str1==*str2)) { str1++; str2++; } return *str1 - *str2; }
四、strcpy函式
strcpy函式:將字串str2(包括NULL)複製到字串str1,返回指向str1的指標。
演算法:將str2中逐個字元新增到str1指向的地址空間,必須保證str1指向的地址空間足夠大。
程式碼如下:
char *strcpy(char *str1, const char *str2)
{
char *p=str1;
assert( (str1!=NULL) && (str2!=NULL) );
while(*str1++=*str2++);
return p;
}
五、atoi函式
atoi函式:把字串轉換成整數。
演算法:首先跳過空格或製表符,再判斷符號,最後通過減去’0’轉化整數,跳過非數值,返回轉換後的整數。
程式碼如下:
int atoi(char *str)
{
int sum=0,sign=1;
char *p=str;
assert(str!=NULL);
if(' '==*p||'\t'==*p)
p++;
if('-'==*p)
sign=-1;
if('-'==*p||'+'==*p)
p++;
while(*p>='0' && *p<='9')
{
sum = sum*10 + *p-'0';
p++;
}
return sign*sum;
}
六、itoa函式
itoa函式:將整數轉化為字串。
演算法:先判斷整數的符號,若為負,則將其轉換為正;將整數從個位到最高位依次存放在臨時陣列tmp中,如果是負整數,則再新增一個負號;逆序將臨時陣列的各個元素放在str字元陣列中,在最後新增一個空字元。
程式碼如下:
void itoa(int num, char str[])
{
int i=0,j=0,sign=num;
char tmp[10];
if(num<0)
num=-num;
do
{
tmp[i++]=num%10 + '0';
num/=10;
}while(num>0);
if(sign<0)
tmp[i++]='-';
tmp[i]='\0';
i--;
while(i>=0)
{
str[j]=tmp[i];
j++;
i--;
}
str[j]='\0';
}
七、strstr函式
strstr函式:搜尋一個字串在另一個字串中的第一次出現。找到所搜尋的字串,則該函式返回第一次匹配的字串的地址;如果未找到所搜尋的字串,則返回NULL。
char *StrStr(const char *string, const char *substring) //呼叫庫函式實現
{
int len1 = strlen(string);
int len2 = strlen(substring);
assert(string != NULL && substring != NULL);
if (len2 > len1)
return NULL; //子串比母串長,返回NULL
while (*string != '\0')
{
if ( (*string == *substring) && (strncmp(string, substring, len2) == 0) ) //(*string == *substring)不成立,則(strncmp(string, substring, len2) == 0)不執行
return (char *)string; //string由const char*轉換為char*
string++; //不可寫在while的迴圈條件裡
}
return NULL;
}
char *StrStr(const char *string, const char *substring) //不呼叫庫函式實現
{
int i, j, tmp;
assert(string != NULL && substring != NULL);
for (i = 0; string[i] != '\0'; i++)
{
tmp = i; //tmp保留主串中的起始判斷下標位置
j = 0;
while (string[i++] == substring[j++])
{
if (substring[j] == '\0')
return (char *)&string[tmp];
}
i = tmp; //將i重新改為tmp
}
return NULL;
}
Wednesday,July 09, 2014 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 補: strncpy、strncmp、strncat、memcpy、memset
char *Strncpy(char *dest, const char *src, unsigned int n)
{
assert(dest != NULL && src != NULL);
char *tmpdest = dest;
while(n-- > 0 && *src != '\0')
*tmpdest++ == *src++;
*tmpdest = '\0';
return dest;
}
int Strncmp(const char *s, const char *t, unsigned int n)
{
assert(s != NULL && t != NULL);
while( *s && *t && (*s == *t) && (n-- > 0) )
{
s++;
t++;
}
return (*s - *t);
}
char *Strncat(char *dest, const char *src, unsigned int n)
{
assert(dest != NULL && src != NULL);
char *tmpdest = dest;
while(*tmpdest != '\0')
tmpdest++;
while(*src && (n-- > 0))
*tmpdest++ = *src++;
*tmpdest = '\0';
return dest;
}
void *Memcpy(void *dest, const void *src, size_t count)
{
assert(dest != NULL && src != NULL);
char *tmpdest = (char *)dest;
char *tmpsrc = (char *)src;
while (count-- > 0)
*tmpdest++ = *tmpsrc++;
return dest;
}
void *Memset(void *buffer, int c, size_t count)
{
assert(buffer != NULL);
char *tmpbuffer = (char *)buffer;
while(count--)
{
*tmpbuffer++ = (char)c;
}
return buffer;
}
2014.9.25