??write in front??
??大家好,我是gugugu。希望你看完之后,能對(duì)你有所幫助,不足請(qǐng)指正!共同學(xué)習(xí)交流??
??本文由 gugugu 原創(chuàng) CSDN首發(fā)?? 如需轉(zhuǎn)載還請(qǐng)通知?
??個(gè)人主頁(yè):gugugu—精品博客
??歡迎各位→點(diǎn)贊?? + 收藏?? + 留言???
??系列專欄:gugugu的精品博客
??我們并非登上我們所選擇的舞臺(tái),演出并非我們所選擇的劇本??
前言
字符函數(shù)和字符串函數(shù)在C語(yǔ)言中是不可缺少的一環(huán),學(xué)會(huì)使用這些函數(shù),會(huì)讓寫(xiě)代碼方便很多,但是只知道這些函數(shù)怎么使用是不夠的,我們更要了解這些函數(shù)是如何實(shí)現(xiàn)的,因此在這篇文章中,會(huì)著重講解如何,模擬實(shí)現(xiàn)這些函數(shù)。
這期內(nèi)容還是比較多的,頭大。
一、字符函數(shù)。
字符函數(shù)分為字符分類函數(shù)和字符轉(zhuǎn)換函數(shù)。
1、字符分類函數(shù)
字符分類函數(shù)有很多,常見(jiàn)的有isupper函數(shù)和islower函數(shù),其他的函數(shù)可以在cplusplus網(wǎng)站中查找
這個(gè)網(wǎng)站真的很好用啊!
注意,字符函數(shù)的頭文件都是<ctype.h>
a、isupper函數(shù)
isupper函數(shù)的作用是判斷一個(gè)字符是不是大寫(xiě)字母
#include <stdio.h>
#include <ctype.h>
int main()
{
char a = 'A';
if (isupper(a))
{
printf("%d , %c\n", isupper(a), a);
}
return 0;
}
如果是大寫(xiě)字母就會(huì)返回一個(gè)非零特殊值,VS中返回的是1
b、islower函數(shù)
islower函數(shù)與isupper函數(shù)的作用剛好相反,是判斷一個(gè)字符是不是小寫(xiě)字母
#include <stdio.h>
#include <ctype.h>
int main()
{
char a = 'q';
if (islower(a))
{
printf("%d ,%c\n", islower(a), a);
}
return 0;
}
如果是小寫(xiě)字母就會(huì)返回一個(gè)特殊值,VS中返回2
c、isupper函數(shù)的模擬實(shí)現(xiàn)
每一個(gè)字符都對(duì)應(yīng)一個(gè)ASCII碼值,大寫(xiě)字母是65到90??梢該?jù)此來(lái)實(shí)現(xiàn)該函數(shù)
#include <stdio.h>
int my_isupper(char a)
{
if (a >= 'A' && a <= 'Z')
return 1;
return 0;
}
int main()
{
char a = 'A';
int ret = my_isupper(a);
if (ret)
{
printf("%d , %c\n", ret, a);
}
return 0;
}
效果如下
d、islower函數(shù)的模擬實(shí)現(xiàn)
道理和isupper的模擬實(shí)現(xiàn)一樣
#include <stdio.h>
int my_islower(char a)
{
if (a >= 'a' && a <= 'z')
return 2;
return 0;
}
int main()
{
char a = 'a';
int ret = my_islower(a);
if (ret)
{
printf("%d , %c\n", ret, a);
}
return 0;
}
效果如下
字符轉(zhuǎn)換函數(shù)
字符轉(zhuǎn)換函數(shù)的頭文件也是<ctype.h>
a、toupper函數(shù)
toupper函數(shù)會(huì)將一個(gè)小寫(xiě)字母轉(zhuǎn)換成一個(gè)大寫(xiě)字母,如果不是小寫(xiě)字母就不會(huì)發(fā)生任何變化。
這就是toupper的功能。
b、tolower函數(shù)
功能與toupper函數(shù)剛好相反
c、toupper函數(shù)的模擬實(shí)現(xiàn)
#include <stdio.h>
int my_toupper(char a)
{
if (a >= 'a' && a <= 'z')
return a - 32;
return a;
}
int main()
{
char a = 'a';
char b = 'A';
char c = ';';
int ret1 = my_toupper(a);
int ret2 = my_toupper(b);
int ret3 = my_toupper(c);
printf("%c %c %c\n", ret1, ret2, ret3);
return 0;
}
d、tolower函數(shù)的模擬實(shí)現(xiàn)
#include <stdio.h>
int my_tolower(char a)
{
if (a >= 'A' && a <= 'Z')
return a + 32;
return a;
}
int main()
{
char a = 'a';
char b = 'A';
char c = ';';
int ret1 = my_tolower(a);
int ret2 = my_tolower(b);
int ret3 = my_tolower(c);
printf("%c %c %c\n", ret1, ret2, ret3);
return 0;
}
字符串函數(shù)就開(kāi)始頭疼了
二、字符串函數(shù)
字符串函數(shù)的對(duì)象是字符串,這很重要,非常容易與后面要學(xué)習(xí)的內(nèi)存函數(shù)搞混
字符串函數(shù)的頭文件是<string.h>
1、strlen函數(shù)
strlen函數(shù),我們應(yīng)該是比較熟悉的,strlen函數(shù)的作用是求一個(gè)字符串的長(zhǎng)度,即‘\0’之前的字符的個(gè)數(shù)。
strlen函數(shù)在使用是的注意事項(xiàng):
a、strlen函數(shù)要正確獲得字符串長(zhǎng)度的話,字符串中必須得有‘\0’
eg. char ch[]={‘a(chǎn)’,‘b’,‘c’}; strlen(ch)就得不到正確答案
b、要關(guān)注strlen函數(shù)的返回值類型是size_t,用%zd打印
注意在判斷大小的時(shí)候size_t一定是大于0的
strlen函數(shù)的模擬實(shí)現(xiàn)
方法一:創(chuàng)建一個(gè)計(jì)數(shù)器
#include <stdio.h>
#include <assert.h>
int my_strlen(char* ch)
{
assert(ch);
int count = 0;
while (*ch != '\0')
{
ch++;
count++;
}
return count;
}
int main()
{
char ch[30] = { 0 };
gets(ch);
int len = my_strlen(ch);
printf("%d\n", len);
return 0;
}
方法二:使用兩個(gè)指針
#include <stdio.h>
#include <assert.h>
int my_strlen(char* ch)
{
assert(ch);
char* start = ch;
while (*ch != '\0')
{
ch++;
}
return ch - start;
}
int main()
{
char ch[30] = { 0 };
gets(ch);
int len = my_strlen(ch);
printf("%d\n", len);
return 0;
}
方法三:利用遞歸實(shí)現(xiàn)
#include <stdio.h>
#include <assert.h>
int my_strlen(char* ch)
{
assert(ch);
if (*ch == '\0')
return 0;
return 1 + my_strlen(ch + 1);
}
int main()
{
char ch[30] = { 0 };
gets(ch);
int len = my_strlen(ch);
printf("%d\n", len);
return 0;
}
大家覺(jué)得那個(gè)方法比較好用?,可以私信博主,哈哈
2、strcpy函數(shù)
cpy是copy的一個(gè)簡(jiǎn)寫(xiě),strcpy函數(shù)也就是字符串拷貝函數(shù)
在使用strcpy函數(shù)時(shí)的注意事項(xiàng)
a、源字符串中必須有’\0’
b、目的數(shù)組必須要足夠大
c、目的數(shù)組必須可以修改
d、標(biāo)準(zhǔn)返回值的類型是char*,更方便觀察
strcpy函數(shù)的作用是將一個(gè)字符數(shù)組的內(nèi)容拷貝到另一個(gè)字符數(shù)組中去
strcpy函數(shù)的模擬實(shí)現(xiàn)
#include <stdio.h>
#include <assert.h>
char* my_strcpy(char* ch1,const char* ch2)
{
assert(ch1 && ch2);
char* ret = ch1;
while (*ch1++ = *ch2++);//這里非常精妙,++不能忘記掉
return ret;
}
int main()
{
char ch1[30] = "###############";
char ch2[30] = "abcdefghi";
char* s = my_strcpy(ch1, ch2);
printf("%s\n", s);
return 0;
}
3、strcat函數(shù)
strcat的作用是字符串追加,將一個(gè)字符串追加到另一個(gè)字符串的后面去。
strcat函數(shù)的使用的注意事項(xiàng)
a、源字符串(知道追加到哪里結(jié)束)和目標(biāo)字符串(知道從哪里開(kāi)始追加)都要有‘\0’
b、目標(biāo)數(shù)組要足夠大(足夠放下兩個(gè)字符串)
c、目標(biāo)數(shù)組要可以修改
d、在使用是目標(biāo)字符串的‘\0’會(huì)被覆蓋
strcat的效果如下
strcat函數(shù)的模擬實(shí)現(xiàn)
#include <stdio.h>
#include <assert.h>
char* my_strcat(char* ch1, const char* ch2)
{
assert(ch1 && ch2);
char* ret = ch1;
while (*ch1 != '\0')
ch1++;
while (*ch1++ = *ch2++);
return ret;
}
int main()
{
char ch1[30] = "###############";
char ch2[30] = "abcdefghi";
char* s = my_strcat(ch1, ch2);
printf("%s\n", s);
return 0;
}
注意,使用strcat時(shí)不能追加自己本身,否則會(huì)因?yàn)椤甛0’被覆蓋,而陷入死循環(huán)。
4、strcmp函數(shù)
進(jìn)行字符串比較,利用字符對(duì)應(yīng)的assic碼值進(jìn)行比較。
如果第一個(gè)字符大于第二個(gè)字符,就返回一個(gè)大于0的數(shù),相等就返回0,小于就返回一個(gè)小于0的數(shù)。
strcmp 函數(shù)的模擬實(shí)現(xiàn)
#include <stdio.h>
#include <assert.h>
int my_strcmp(const char* ch1, const char* ch2)
{
assert(ch1 && ch2);
while (*ch1 == *ch2)
{
if (*ch1 == '\0')
return 0;
ch1++;
ch2++;
}
return *ch1 - *ch2;//這一步比較巧妙
}
int main()
{
char ch1[30] = { 0 };
char ch2[30] = { 0 };
gets(ch1);
gets(ch2);
int ret = my_strcmp(ch1, ch2);
if (ret > 0)
printf(">\n");
else if (ret < 0)
printf("<\n");
else
printf("==\n");
return 0;
}
幾個(gè)比較常用的基本函數(shù)講完了,下面的是引申的函數(shù)和不常用的函數(shù)。
5、strncat函數(shù)
strncat函數(shù)比起strcat函數(shù)多了一個(gè)n,n表示個(gè)數(shù),也就是說(shuō)strncat可以控制追加字符串的字符個(gè)數(shù)。
功能比較簡(jiǎn)單,就不介紹了,直接進(jìn)行函數(shù)的模擬實(shí)現(xiàn)。
#include <stdio.h>
#include <assert.h>
char* my_strncat(char* ch1, const char* ch2, size_t num)
{
assert(ch1 && ch2);
char* ret = ch1;
while (*ch1 != '\0')
ch1++;
while (num--)
{
*ch1 = *ch2;
if (*ch2 == '\0')
return ret;
ch1++;
ch2++;
}
return ret;
}
int main()
{
char ch1[30] = { 0 };
char ch2[30] = { 0 };
gets(ch1);
gets(ch2);
size_t n = 0;
scanf("%zd", &n);
char* s = my_strncat(ch1, ch2, n);
printf("%s\n", s);
return 0;
}
6、strncpy函數(shù)
同上,可以拷貝n 個(gè)字符到另一個(gè)字符串中。
功能和上面相似,就不介紹了,直接進(jìn)行模擬實(shí)現(xiàn)
#include <stdio.h>
#include <assert.h>
#include <string.h>
char* my_strncpy(char* ch1, const char* ch2, size_t num)
{
assert(ch1 && ch2);
char* ret = ch1;
int len = strlen(ch2);
if (len > num)
{
while (num--)
{
*ch1++ = *ch2++;
}
*ch1 = '\0';
}
else
{
while (num--)
{
if (*ch2 != '\0')
*ch1++ = *ch2++;
else
*ch1 = '\0';
}
}
return ret;
}
int main()
{
char ch1[30] = { 0 };
char ch2[30] = { 0 };
gets(ch1);
gets(ch2);
size_t n = 0;
scanf("%zd", &n);
char* s = my_strncpy(ch1, ch2, n);
printf("%s\n", s);
return 0;
}
7、strncmp函數(shù)
功能還是與上面的函數(shù)功能相似,直接進(jìn)行函數(shù)模擬實(shí)現(xiàn)
#include <stdio.h>
#include <assert.h>
int my_strncmp(const char* ch1, const char* ch2, size_t num)
{
assert(ch1 && ch2);
while (num--)
{
if (*ch1 == *ch2)
{
ch1++;
ch2++;
}
else
return *ch1 - *ch2;
}
return 0;
}
int main()
{
char ch1[30] = { 0 };
char ch2[30] = { 0 };
gets(ch1);
gets(ch2);
size_t n = 0;
scanf("%zd", &n);
int ret = my_strncmp(ch1, ch2, n);
if (ret > 0)
printf(">\n");
else if (ret < 0)
printf("<\n");
else
printf("==\n");
return 0;
}
他來(lái)了,稀有函數(shù)來(lái)啦!
8、strtok函數(shù)
這個(gè)函數(shù)比較陌生,功能也比較奇怪。
他的作用是,在一個(gè)字符串中提取出特定的分割符之間的內(nèi)容。
我們以一個(gè)郵箱為例來(lái)進(jìn)行講解。
假設(shè)有一個(gè)郵箱為gugugu@cl.com
其中的分割符就是@和.
我們想要提取出三段內(nèi)容怎么辦?
這時(shí)就可以使用strtok函數(shù)了。
這樣子就可以實(shí)現(xiàn)啦!
strtok 比較特殊,他的參數(shù)有兩種方式,一種是傳遞數(shù)組名和分割符,這樣子,返回值就是第一段的起始地址,另一種參數(shù)是傳遞空指針和分割符,這樣子,返回值就是下一段的起始地址。
strtok實(shí)現(xiàn)方法比較復(fù)雜,這里就不進(jìn)行講解,只需要知道其中利用到了static關(guān)鍵字即可。
9、strstr函數(shù)
顧名思義strstr是兩個(gè)字符串,這個(gè)函數(shù)的作用就是在一個(gè)字符串中去找另一個(gè)字符串。
先看看他的功能。
strstr函數(shù)是在字符串中找一個(gè)子字符串,在字符串一中找字符串二第一次出現(xiàn)的位置,如果找到了返回第一次出現(xiàn)的地址,找不到返回空指針
注意,當(dāng)?shù)诙€(gè)字符串為空時(shí),返回第一個(gè)字符串的首地址
strstr函數(shù)的模擬實(shí)現(xiàn)有兩種方法
先講述暴力求解的方法,雖然比較暴力,但是也是比較精妙的。
#include <stdio.h>
#include <assert.h>
char* my_strstr(const char* ch1, const char* ch2)
{
assert(ch1 && ch2);
const char* cp = ch1;
const char* s1 = NULL;
const char* s2 = NULL;
while (*cp)
{
s1 = cp;
s2 = ch2;
while (*s1 == *s2&&s1&&s2)
{
s1++;
s2++;
}
if (*s2 == '\0')
return cp;
cp++;
}
return NULL;
}
int main()
{
char ch1[30] = "abcdefghi";
char ch2[30] = "def";
char* s = my_strstr(ch1, ch2);
printf("%s\n", s);
return 0;
}
利用cp去記住每一個(gè)可能的地址,在用兩個(gè)指針s1和s2去檢驗(yàn)cp是否是正確的,如果不正確就換一個(gè)cp,按照這個(gè)思路就可以實(shí)現(xiàn)。
方法二KMP算法,該算法比較復(fù)雜,難以理解,有興趣可以自行學(xué)習(xí),這里就不去講解了。
下面這個(gè)函數(shù)巨帥?。?!
10、strerror函數(shù)
這個(gè)函數(shù)比較有意思
strerror函數(shù)返回一個(gè)錯(cuò)誤碼所對(duì)應(yīng)的錯(cuò)誤信息字符串的起始地址
單獨(dú)看這句話還是比較難理解的,先看個(gè)例子吧。
但是每次使用的時(shí)候,不可能這么使用,畢竟這么寫(xiě)開(kāi)起來(lái)還是很呆的。
這樣寫(xiě),是不是頓時(shí)高級(jí)多了,哈哈哈。
注意:errno的頭文件為<errno.h>
11、perror函數(shù)
既然介紹了strerror函數(shù),那么perror函數(shù)就必不可少了。
perror函數(shù)是打印錯(cuò)誤信息的函數(shù)。
perror函數(shù),print error message 打印錯(cuò)誤信息,頭文件為<stdio.h>
要注意的是perror函數(shù)的錯(cuò)誤信息也是從errno中得到的。
舉個(gè)例子看看效果
相當(dāng)于比strerror函數(shù)多了一個(gè)打印功能。
那是不是意味著perror函數(shù)就可以替代strerror函數(shù)了呢?
很明顯是不能的。
如果要打印錯(cuò)誤信息,直接使用perror,如果要保存錯(cuò)誤信息,使用strerror
好啦,今天的分享就到此結(jié)束了。
明天再見(jiàn)。
!?。。。。。。。。。。。。。。。?!求關(guān)注!?。。。。。。。。。。。。。。。。。?!
?。。。。。。。。。。。。。。。。?mark>一鍵三連吧?。。。。。。。。。。。。。。。。。?!文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-715598.html
文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-715598.html
到了這里,關(guān)于【C語(yǔ)言】字符函數(shù)和字符串函數(shù)的詳細(xì)教學(xué)和模擬實(shí)現(xiàn)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!