**str系列函數的由來**
字符串是一中重要的數據類型,但C語言並沒有顯式的字符串數據類型,因爲字符串以字符串常量的形式出現或存儲於字符數組中。字符串常量很適用於那些不會對它們進行修改的程序。所有其他字符串都必須存儲於字符數組或動態內存的分配中。因此就出現了處理字符串的一系列函數,下面讓我們一一來認識這些函數。
1、strlen 求字符串長度
字符串長度就是它所包含的字符個數,例如char *str=”abcdef”;那麼它的長度就是6
注:(1)求字符串長度只計算字符個數,不算末尾的\0
(2)strlen的返回值是一個無符號整數類型,而在表達式中使用無符號數可能會導致無法預料的結果,例如:
if(strlen(x)>=strlen(y))
if(strlen(x)-strlen(y)>=0)
這兩個語句是不相等的,第一條語句會得到你預想的結果但是第二條語句卻不會按照你的想法來,因爲它的結果永遠爲真,因爲strlen的結果是無符號數,而無符號數的運算結果永遠大於0;
瞭解清楚注意事項之後我們來自己模擬實現strlen,在此會有三種模擬方法:
方法1:使用計數器
int my_strlen(const char *str)
{
int count = 0;
assert(str != NULL);
while (*str)
{
count++;
*str++;
}
return count;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
方法2:指針減指針的方式
int strlen(const char *str)
{
const char *start = NULL;
assert(str != NULL);
start = str;
while (*str)
{
*str++;
}
return str-start;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
方法3:用遞歸的方式實現
int strlen(const char *str)
{
if (*str != '\0')
{
return 1 + strlen(++str);
}
else
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
2、不受限制的複製字符串拷貝函數strcpy
何謂“不受限制”呢?最常用的字符串都是不受限制的,所謂的不受限制就是說它們只是通過尋找字符串結尾的‘\0’來判斷它的長度。這些函數一般都指定一塊內存用於存放結果字符串。在使用這些函數時,程序員必須保證結果字符串不會溢出這塊內存。
strcpy是字符串拷貝函數,它的原型如下:
char *strcpy(char *dst,const char *src);
這個函數的作用是把src的內容賦給dst;使用這個函數有以下幾個注意事項:
1、如果參數src和dst在內存中出現重疊現象,其結果是未定義的;
2、由於dst參數將進行修改,所以它必須是一個“字符數組”或“指向動態分配內存的數組的指針”,不能使用字符串常量;
3、目標參數以前的內容將被覆蓋並丟失。即使源字符串比目標字符串更短,目標字符串最後剩餘的字符也會丟失。
瞭解了該函數的注意事項之後,我們來模擬實現一下:
char *my_strcpy(char *dst, const char *src)
{
char *ret = dst;
assert(dst);
assert(src);
while (*src != '\0')
{
*dst++ = *src++;
}
return ret;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
注:使用strcpy函數把一個長字符串複製到一個較
短的數組中,導致溢出。
3、受限制的複製字符串拷貝函數strncpy
何謂“受限制”呢?標準庫中還包含了一些函數,它們以一種不同的方式處理字符串。這些函數接受一個顯示的長度參數,用於限定進行復制或比較的字符數。這些函數提供了一種方便的機制,可以防止難以預料的長字符串從它們的目標數組溢出。
strncpy的函數原型如下:
char *strncpy(char *dst,const char *src,size_t len)
注:strncpy 調用的結果可能不是一個字符串,因此字符串必須以‘\0’結尾,也就是說對目標字符串結尾用‘\0’進行填充。
瞭解了注意事項之後,我們就來模擬實現一下strncpy函數:
char *my_strncpy(char *dst, const char *src, int len)
{
assert(dst!=NULL);
assert(src!=NULL);
char *pdst = dst;
while (len--)
{
*dst++ = *src++;
}
*dst= '\0';
return pdst;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
4、連接字符串函數strcat
strcat 函數的作用是把一個字符串(源字符串)添加到另一個字符串(目標字符串)的後面,它的函數原型如下:
char *strcat(char *dst,const char *src);
注:(1)目標字符串也可以是空字符串;
(2)必須保證目標字符串數組剩餘的空間足以保存整個源字符串;
(3)不能自己給自己追加。
瞭解了注意事項之後,我們來模擬實現以下該函數:
char *my_strcat(char *dst, const char *src)
{
char *pdest = dst;
assert(dst);
assert(src);
while (*dst)
{
dst++;
}
while (*src)
{
*dst++ = *src++;
}
return pdest;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
5、受限制的連接字符串函數strncat
strncat的作用跟strcat的作一樣,都是將源字符串的內容追加到目標字符串後面,但是strncat有限制,該限制就是追加多少個字符由你自己來定,加入源字符串中有6個字符,你可以選擇追加10個,當然前提是目標字符串中能容納得下。
strncat的注意事項跟strcat的注意事項相同,下面我們來模擬實現一下strncat:
char *my_strncat(char *dst, const char *src,int len)
{
char *pdest = dst;
assert(dst);
assert(src);
while (*dst)
{
dst++;
}
while (len&&*src)
{
*dst++ = *src++;
len--;
}
*dst = '\0';
return pdest;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
6、字符串比較函數strcmp
比較兩個字符串是對兩個字符串中的字符逐個進行比較,例如將字符串s1=“abcd”和字符串s2=“abcc”進行比較,將s1中的第一個字符‘a’的ASCII值和s2中的第一個字符‘a’的ASCII值進行比較,發現相等,然後再接着比較兩個字符串中的第二組字符,直到不相等爲止,在該例中發現s1中的‘d’和s2中的‘c’不相等,就停止比較。此時如果‘d’大於‘c’就認爲s1>s2; 如果‘d’小於‘c’或者s1是s2的子串就認爲s1< s2;如果兩個字符串完全相等,則認爲s1=s2。
該函數的原型如下:
int strcmp(const chat *s1, const char *s2);
瞭解了比較的原理之後我們再來看一下注意事項:
注:(1)如果s1>s2,則函數返回任意一個大於零的數,
意一個小於零的數,如果s1=s2,則函數返回一個等於零的數;
(2)由於strcmp並不修改它的任何一個參數,所以不存在溢出字符數組的危險;
(3)strcmp函數的字符串參數也必須以‘\0’結尾,否則的話,它將對參數後面的內容進行比較,這個比較沒有意義。
現在我們來模擬實現一下該函數:
int my_strcmp(const char *s1, const char *s2)
{
assert(s1);
assert(s2);
while (*s1 == *s2)
{
if (*s1 == '\0')
return 0;
*s1++;
*s2++;
}
return *s1 - *s2;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
7、受限制的字符串比較函數strncmp
該函數的原型是:
int (const char *s1,const char *s2,size_t len);
函數說明:
strcmp也用於比較兩個字符串,但是它最多比較len個字節,如果兩個字符串在第len個字符前存在不相等的字符,就停止比較,並返回結果。如果兩個字符串的前len字符相等,函數就返回零。
該函數的注意事項和strcmp相同,瞭解了這些內容之後,我們來模擬實現一下該函數:
int my_strncmp(const char *s1, const char *s2, int len)
{
assert(s1);
assert(s2);
while (len-- && *s1 &&(*s1==*s2))
{
s1++;
s2++;
}
return *s1 - *s2;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
8、查找子字符串函數strstr
該函數的函數原型如下:
char *strstr(const char *s1,const char *s2);
函數說明:
該函數查找字符串s1中首次出現s2的位置,並返回一個指向該位置的指針;如果字符串s2並沒有完整的出現在s1的任何地方,函數將返回一個空指針;如果字符串s2爲空字符串,函數將返回s1。
注:在模擬該函數時,應當考慮全面,如:
s1=”abbbcde”
s2=”bbc”
這種情況。
了清楚之後我們來模擬實現一下該函數:
char *my_strstr(const char *s1, const char *s2)
{
char *ps1 = (char *)s1;
char *ps2 = (char *)s2;
char *cp = (char *)s1;
assert(s1);
assert(s2);
while (*cp!='\0')
{
ps1=cp;
while ((*ps1 == *ps2) && *ps1 && *ps2)
{
ps1++;
ps2++;
}
if (*ps2 == '\0')
return cp;
ps2 = (char *)s2;
cp++;
}
return NULL;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
9、模擬實現strrstr函數
strstr函數是找子字符串第一次出現的位置,而strrstr是找最後一次出現的位置,如:
s1=“abbbcdefbbcjik”;
s2=”bbc”;
則函數返回”bbcjik”,該函數有兩種模擬實現的方式,一種是藉助庫函數strstr來實現,一種是不借助strstr實現
第一種實現方式:藉助strstr來實現:
char *my_strrstr(const char *s1, const char *s2)
{
const char *ps1 = NULL;
const char *last = NULL;
assert(s1);
assert(s2);
if (!*s2)
return (char *)s1;
while (ps1=strstr(s1,s2))
{
last = ps1;
s1 = ps1 + 1;
}
return (char *)last;
return NULL;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
第二種:不借助strstr實現:
char *my_strrstr(const char *str, const char *src)
{
assert(str);
assert(src);
int len1 = strlen(str);
int len2 = strlen(src);
char *strend = (char *)str + len1 - 1;
char *start = (char *)src;
char *srcend = (char *)src + len2 - 1;
while (*strend != *srcend)
{
strend--;
}
char *cp = strend;
while (start != srcend)
{
if (*cp== *srcend)
{
cp--;
srcend--;
}
}
return cp;
return NULL;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
10、strchr函數:在字符串中查找一個特定的字符第一次出現的位置
該函數的函數原型如下:
char *strchr(const char *str,int ch);
注:改函數的第二個參數是一個整型值。但是,它包含了一個字符值。strchr函數在字符串str中查找字符ch第一次出現的位置,找到後函數返回一個指向該位置的指針,如果該字符並不存在與該字符串中,則返回一個NULL指針。
該函數的實現如下:
char *my_strchr(const char *str,int ch)
{
assert(str);
while (*str)
{
if (*str == ch)
{
return (char *)str;
}
str++;
}
return NULL;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
11、strrchr函數:在字符串中查找一個特定的字符最後一次出現的位置
該函數的原型如下:
char *strrchr( const char *str,int ch);
strrchr的功能和strchr基本一致,只是它返回的是一個指向字符串中該字符最後一次出現的位置。
該函數的實現如下:
char *my_strrchr(const char *str, char c)
{
const char *start = str;
while (*str)
{
str++;
}
str--;
while (str >= start)
{
if (*str == c)
{
return (char *)str;
}
str--;
}
return NULL;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
還有其他的一些字符串系列函數,由於不常用就不在此一一實現了,只要知道它們的用法即可。