C/C++字符函數(shù)和字符串函數(shù)示例詳解
前言
在編程的過程中,我們經(jīng)常要處理字符和字符串,為了?便操作字符和字符串,C語?標(biāo)準(zhǔn)庫中提供了 ?系列庫函數(shù),接下來我們就學(xué)習(xí)?下這些函數(shù)。
字符函數(shù)和字符串函數(shù)
1.字符分類函數(shù)
C語?中有?系列的函數(shù)是專?做字符分類的,也就是?個字符是屬于什么類型的字符的。 這些函數(shù)的使?都需要包含?個頭?件是 ctype.h
這些函數(shù)的使??法?常類似,我們就講解?個函數(shù)的事情,其他的?常類似:
int islower ( int c );
islower 是能夠判斷參數(shù)部分的 c 是否是?寫字?的。 通過返回值來說明是否是?寫字?,如果是?寫字?就返回?0的整數(shù),如果不是?寫字?,則返回 0。
練習(xí):
寫?個代碼,將字符串中的?寫字?轉(zhuǎn)?寫,其他字符不變。
#include <stdio.h> #include <ctype.h> int main () { int i = 0; char str[] = "Test String.\n"; char c; while (str[i]) { c = str[i]; if (islower(c)) c -= 32; putchar(c); i++; } return 0; }
也可以寫成
while(str[i]!='\0') { if(islower(str[i])) { str[i]=toupper(str[i]); } i++; }
2.字符轉(zhuǎn)換函數(shù)
C語?提供了2個字符轉(zhuǎn)換函數(shù):
int tolower ( int c ); //將參數(shù)傳進(jìn)去的?寫字?轉(zhuǎn)?寫 int toupper ( int c ); //將參數(shù)傳進(jìn)去的?寫字?轉(zhuǎn)?寫
上?的代碼,我們將?寫轉(zhuǎn)?寫,是-32完成的效果,有了轉(zhuǎn)換函數(shù),就可以直接使? tolower 函 數(shù)。
#include <stdio.h> #include <ctype.h> int main () { int i = 0; char str[] = "Test String.\n"; char c; while (str[i]) { c = str[i]; if (islower(c)) c = toupper(c); putchar(c); i++; } return 0; }
3.strlen的使用和模擬實現(xiàn)
size_t strlen ( const char * str );//size_t是無符號整型
功能:統(tǒng)計參數(shù) str 指向的字符串的?度。統(tǒng)計的是字符串中 ‘\0’ 之前的字符的個數(shù)。
參數(shù):
• str :指針,指向了要統(tǒng)計?度的字符串。 返回值:返回了 str 指向的字符串的?度,返回的?度不會是負(fù)數(shù),所以返回類型是 size_t 。
if((strlen("abc")-strlen("abcdef"))>0)//size_t為無符號整型,所以3-6一定大于0 { printf(">\n");//所以輸出> } else { printf("<=\n"); }
解決方案
(int)strlen("abc")-(int)strlen("abcdef")
3.1 代碼演示
#include <stdio.h> #include <string.h> int main() { const char* str = "abcdef"; printf("%zd\n", strlen(str)); return 0; }
使?注意事項:
• 字符串以 ‘\0’ 作為結(jié)束標(biāo)志,strlen函數(shù)返回的是在字符串中 ‘\0’ 前?出現(xiàn)的字符個數(shù)(不包 含 ‘\0’ )。
• 參數(shù)指向的字符串必須要以 ‘\0’ 結(jié)束。
• 注意函數(shù)的返回值為 size_t ,是?符號的( 易錯 )
• strlen的使?需要包含頭?件
3.2 strlen返回值
#include <stdio.h> #include <string.h> int main() { const char* str1 = "abcdef"; const char* str2 = "bbb"; if(strlen(str2) - strlen(str1) > 0)//size_t類型恒大于0 { printf("str2 > str1\n"); } else { printf("srt1 > str2\n"); } return 0; }
3.3 strlen的模擬實現(xiàn)
?式1:
//計數(shù)器?式 int my_strlen(const char * str) { int count = 0; assert(str);//assert斷言 頭文件<assert.h> while(*str) { count++; str++; } return count; }
?式2:
//不能創(chuàng)建臨時變量計數(shù)器 int my_strlen(const char * str) { assert(str); if(*str == '\0') return 0; else return 1 + my_strlen(str+1);//str+1是下一個字符的地址 }
比如 my_strlen("abcdef")=1+my_strlen("bcdef")
?式3:
//指針-指針的?式 int my_strlen(char *s) { assert(str); char *p = s; while(*p != '\0') p++; return p - s; }
4.strcpy的使用和模擬實現(xiàn)
string copy
char* strcpy(char * destination, const char * source );
功能:字符串拷?,拷?到源頭字符串中的 \0 為?
參數(shù):
destination :指針,指向?的地空間
source :指針,指向源頭數(shù)據(jù)
返回值:
strcpy 函數(shù)返回的?標(biāo)空間的起始地址
4.1 代碼演示
#include <stdio.h> #include <string.h> int main() { char arr1[10] = {0}; char arr2[] = "hello"; strcpy(arr1, arr2);//\0也會拷貝進(jìn)去 printf("%s\n", arr1); return 0; }
使?注意事項:
•源字符串必須以 ‘\0’ 結(jié)束.。
• 會將源字符串中的 ‘\0’ 拷?到?標(biāo)空間。
• ?標(biāo)空間必須?夠?,以確保能存放源字符串。
• ?標(biāo)空間必須可修改。(不能是常量字符串,因為常量字符串不可以修改)
4.2 模擬實現(xiàn)
#include <stdio.h> #include <assert.h> //1.參數(shù)順序 //2.函數(shù)的功能,停?條件 //3.assert //4.const修飾指針 //5.函數(shù)返回值 char* my_strcpy(char *dest, const char*src)//src不能修改 { char *ret = dest;//dest++后變了 所以先存起來 assert(dest != NULL); assert(src != NULL); while((*dest++ = *src++))//先用再++,當(dāng)*src為\0時,終止循環(huán) { ; } return ret; } int main() { char arr1[10] = {0}; char arr2[] = "hello"; my_strcpy(arr1, arr2); printf("%s\n", arr1); return 0; }
void my_strcpy(char* dest,char* src) { //拷貝\0前面的內(nèi)容 while(*src!='\0') { *dest=*src; dest++; src++; } *dest=*src;//拷貝\0 }
5.strcat的使用和模擬實現(xiàn)
連接字符串
char * strcat ( char * destination, const char * source );
功能:字符串追加,把 source 指向的源字符串中的所有字符都追加到 destination 指向的空間 中。
參數(shù):
destination :指針,指向?的地空間
source :指針,指向源頭數(shù)據(jù)
返回值:
strcat 函數(shù)返回的?標(biāo)空間的起始地址
5.1 代碼演示
#include <stdio.h> #include <string.h> int main() { char arr1[20] = "hello "; char arr2[] = "world"; strcat(arr1, arr2); printf("%s\n", arr1); return 0;//輸出hello world }
使用注意事項:
• 源字符串必須以 ‘\0’ 結(jié)束。
• ?標(biāo)字符串中也得有 \0 ,否則沒辦法知道追加從哪?開始。
• ?標(biāo)空間必須有?夠的?,能容納下源字符串的內(nèi)容。
• ?標(biāo)空間必須可修改。
5.2 模擬實現(xiàn)
#include <stdio.h> #include <assert.h> char* my_strcat(char *dest, const char*src) { char *ret = dest; assert(dest != NULL); assert(src != NULL);//這兩行等價于assert(dest&&src) //1.找到目標(biāo)空間中的\0 while(*dest)//while(*dest!='\0') { dest++; } while((*dest++ = *src++)) { ; } return ret; } int main() { char arr1[20] = "hello "; char arr2[] = "world"; my_strcat(arr1, arr2); printf("%s\n", arr1); return 0; }
那如果是自拼接呢
my_strcat(arr1,arr1) //自拼接會:1.死循環(huán)2.系統(tǒng)崩潰
6.strcmp的使用和模擬實現(xiàn)
兩個字符串比較應(yīng)用場景 登錄: 輸入 :用戶名 密碼
? 數(shù)據(jù)庫 用戶名 密碼
int strcmp ( const char * str1, const char * str2 );
功能:?來?較 str1 和 str2 指向的字符串,從兩個字符串的第?個字符開始?較,如果兩個字符 的ASCII碼值相等,就?較下?個字符。直到遇到不相等的兩個字符,或者字符串結(jié)束。
參數(shù):
str1 :指針,指向要?較的第?個字符串
str2 :指針,指向要?較的第?個字符串
返回值:
• 標(biāo)準(zhǔn)規(guī)定:
? 第?個字符串?于第?個字符串,則返回?于0的數(shù)字
? 第?個字符串等于第?個字符串,則返回0
? 第?個字符串?于第?個字符串,則返回?于0的數(shù)字
6.1 代碼演示:
#include <stdio.h> #include <string.h> int main() { char arr1[] = "abcdef"; char arr2[] = "abq"; int ret = strcmp(arr1, arr2); printf("%d\n", ret); if(ret > 0) printf("arr1 > arr2\n"); else if(ret == 0) printf("arr1 == arr2\n"); else printf("arr1 < arr2\n"); return 0; }
6.2 模擬實現(xiàn):
int my_strcmp (const char * str1, const char * str2) { int ret = 0 ; assert(str1 != NULL); assert(str2 != NULL); while(*str1 == *str2) { if(*str1 == '\0') return 0; str1++; str2++; } return *str1-*str2;//最后比較的ASII碼值的差 }
7.strncpy函數(shù)的使用
strcpy strcat strcmp 是長度不受限的字符串比較 不安全
strncpy strncat strncmp 長度受限函數(shù)
char * strncpy ( char * destination, const char * source, size_t num );
功能:字符串拷?;將 source 指向的字符串拷?到 destination 指向的空間中,最多拷? num 個字符。
參數(shù):
destination :指針,指向?的地空間
source :指針,指向源頭數(shù)據(jù)
num :從source指向的字符串中最多拷?的字符個數(shù)
返回值:
strncpy 函數(shù)返回的?標(biāo)空間的起始地址
7.1 代碼演示
#include <stdio.h> #include <string.h> int main() { char arr1[20] = {0}; char arr2[] = "abcdefghi"; char* str = strncpy(arr1, arr2, 5); printf("%s\n", arr1); printf("%s\n", str); return 0; }
長度足夠,讓拷貝幾個就幾個,長度小于num補\0
7.2 ?較strcpy和strncpy函數(shù)
strcpy 函數(shù)拷?到 \0 為?,如果?標(biāo)空間不夠的話,容易出現(xiàn)越界?為。
strncpy 函數(shù)指定了拷?的?度,源字符串不?定要有 \0 ,同時在設(shè)計參數(shù)的時候,就會多?層 思考:?標(biāo)空間的??是否夠?, strncpy 相對 strcpy 函數(shù)更加安全。
8.strncat函數(shù)的使用
char * strncat ( char * destination, const char * source, size_t num );
功能:字符串追加;將 source 指向的字符串的內(nèi)容,追加到 destination 指向的空間,最多追 加 num 個字符。
參數(shù):
destination :指針,指向了?標(biāo)空間
source :指針,指向了源頭數(shù)據(jù)
num :最多追加的字符的個數(shù)
返回值:返回的是?標(biāo)空間的起始地址
8.1 代碼演示
#include <stdio.h> #include <string.h> int main() { char arr1[20] = "hello "; char arr2[] = "world"; char* str = strncat(arr1, arr2, 5);//從\0開始追加,追加萬還加\0 printf("%s\n", arr1); printf("%s\n", str);//若num>長度,則追加\0 return 0; }
8.2 strcat和strncat對比
• 參數(shù)不同, strncat 多了?個參數(shù)
• strcat 函數(shù)在追加的時候要將源字符串的所有內(nèi)容,包含 \0 都追加過去,但是 strncat 函 數(shù)指定了追加的?度。
• strncat 函數(shù)中源字符串中不?定要有 \0 了。
• strncat 更加靈活,也更加安全。
9.strncmp函數(shù)的使用
int strncmp ( const char * str1, const char * str2, size_t num );
功能:字符串?較;?較 str1 和 str2 指向的兩個字符串的內(nèi)容,最多?較 num 字符。
參數(shù):
str1 :指針,指向?個?較的字符串
str2 :指針,指向另外?個?較的字符串
num :最多?較的字符個數(shù)
返回值:
• 標(biāo)準(zhǔn)規(guī)定:
? 第?個字符串?于第?個字符串,則返回?于0的數(shù)字
? 第?個字符串等于第?個字符串,則返回0
? 第?個字符串?于第?個字符串,則返回?于0的數(shù)字
9.1 代碼演示
#include <stdio.h> #include <string.h> int main() { char arr1[] = "abcdef"; char arr2[] = "abcqw"; int ret1 = strncmp(arr1, arr2, 3); printf("%d\n", ret1); int ret2 = strncmp(arr1, arr2, 4); printf("%d\n", ret2); return 0; }
9.2 strcmp和strncmp?較
• 參數(shù)不同
• strncmp可以?較任意?度了
• strncmp函數(shù)更加靈活,更加安全
10.strstr的使用和模擬實現(xiàn)
char * strstr ( const char * str1, const char * str2);
功能:strstr 函數(shù),查找 str2 指向的字符串在 str1 指向的字符串中第?次出現(xiàn)的位置。 簡??之:在?個字符串中查找?字符串。 strstr 的使?得包含<string.h>
參數(shù):
str1 :指針,指向了被查找的字符串
str2 :指針,指向了要查找的字符串
返回值:
• 如果str1指向的字符串中存在str2指向的字符串,那么返回第?次出現(xiàn)位置的指針
• 如果str1指向的字符串中不存在str2指向的字符串,那么返回NULL(空指針)
10.1 代碼演示
/* strstr example */ #include <stdio.h> #include <string.h> int main () { char str[] ="This is a simple string"; char * pch; pch = strstr (str,"simple"); if (pch != NULL) printf("%s\n", pch); else printf("查找的字符串不存在\n"); return 0; }
int main() { char arr1[]="this is an apple\n"; const char* p="is";//放的是i的地址 char* ret = strstr(arr1,p); printf("%s\n",ret); return 0; }
10.2 strstr的模擬實現(xiàn)
char * strstr (const char * str1, const char * str2)//str1 str2不希望被修改 { char *cp = (char *) str1; char *s1, *s2; //特殊情況:str2是空字符串時,直接返回str1 if ( !*str2 ) return((char *)str1); while (*cp) { s1 = cp; s2 = (char *) str2; while ( *s1 && *s2 && !(*s1-*s2) ) s1++, s2++; if (!*s2) return(cp); //返回第?次出現(xiàn)的起始 cp++; } return(NULL); //找不到則返回NULL }
先來一種簡單情況 在abcdef 中找 bcd
str1指向a時,不符合,所以++指向b,此時與*str2相等,然后str2++,再str1++,直到str2指向\0時結(jié)束
再來一種復(fù)雜情況
從第一個b開始時沒有 可能存在多次匹配 還得有兩個指針變量 存放他們兩個的起始變量 然后對他們++ 讓起始位置向后平移
char* my_strstr(const char* str1,const char* str2) { const char* s1=NULL; const char* s2=NULL; const char* cur=str1; while(*cur) { s1=cur; s2=str2; while(*s1!='\0'&&*s2!='\0'&&*s1==*s2) { s1++; s2++; } if(*s2=='\0') { return char* cur; } cur++; } return NULL; }
strstr函數(shù)的實現(xiàn)有多種,可以暴?查找,也有?種?效?些的算法:KMP,有興趣的可以去學(xué)習(xí)。
11.strtok函數(shù)的使用
char *strtok(char *str, const char *delim); //delim參數(shù)指向了一個字符串,定義了用作分隔符的字符的集合
功能
• 分割字符串:根據(jù)delim 參數(shù)中指定的分隔符,將輸?字符串str 拆分成多個?字符串。
• 修改原始字符串: strtok 會直接在原始字符串中插?’\0’ 終?符,替換分隔符的位置,因 此原始字符串會被修改。
參數(shù)
1.str :?次調(diào)?時傳?待分割的字符串;后續(xù)調(diào)?傳?NULL ,表?繼續(xù)分割同?個字符串。
2.delim :包含所有可能分隔符的字符串(每個字符均視為獨?的分隔符)。
返回值
• 成功時返回指向當(dāng)前?字符串的指針。
• 沒有更多?字符串時返回NULL 。
使?步驟
- ?次調(diào)?:傳?待分割字符串和分隔符。
- 后續(xù)調(diào)?:傳?NULL 和相同的分隔符,繼續(xù)分割。
- 結(jié)束條件:當(dāng)返回NULL 時,表?分割完成。
11.1 代碼演示
int main() { char arr[]="fnianxu@yeah.net"; char arr2[30]={0};//"fnianxu\0yeah\0net" strcpy(arr2,arr); const char* sep="@.";//傳入NULL在\0之后繼續(xù)進(jìn)行 char* ret=NULL;//初始化 ret = strtok(arr2,sep); printf("%s\n",ret); ret = strtok(NULL,sep); printf("%s\n",ret); ret = strtok(NULL,sep); printf("%s\n",ret); }
運行結(jié)果如下:
但一直傳入空指針有些麻煩,所以看以下示例
#include <stdio.h> #include <string.h> int main() { char arr[] = "192.168.6.111"; const char* sep = "."; const char* str = NULL; char buf[30] = {0}; strcpy(buf, arr); //將arr中的字符串拷?到buf中,對buf的內(nèi)容進(jìn)?切割 for (str = strtok(buf, sep); str != NULL; str = strtok(NULL, sep)) { printf("%s\n", str); } return 0; }
11.2 注意事項
• 破壞性操作: strtok 會直接修改原始字符串,將其中的分隔符替換為’\0’ 。如果需要保留原字符串,應(yīng)先拷??份。
• 連續(xù)分隔符:多個連續(xù)的分隔符會被視為單個分隔符,不會返回空字符串。
• 空指針處理:如果輸?的str 為NULL 且沒有前序調(diào)?,?為未定義。
12.strerror函數(shù)的使用
char* strerror ( int errnum );
功能
1.strerror 函數(shù)可以通過參數(shù)部分的errnum 表示錯誤碼,得到對應(yīng)的錯誤信息,并且返回這個錯誤信息字符串?字符的地址。
2.strerror 函數(shù)只針對標(biāo)準(zhǔn)庫中的函數(shù)發(fā)?錯誤后設(shè)置的錯誤碼的轉(zhuǎn)換。
3.strerror 的使?需要包含<string.h>
在不同的系統(tǒng)和C語?標(biāo)準(zhǔn)庫的實現(xiàn)中都規(guī)定了?些錯誤碼,?般是放在 errno.h 這個頭?件中說 明的,C語?程序啟動的時候就會使??個全局的變量 errno 來記錄程序的當(dāng)前錯誤碼,只不過程序啟動的時候errno 是0,表?沒有錯誤,當(dāng)我們在使?標(biāo)準(zhǔn)庫中的函數(shù)的時候發(fā)?了某種錯誤, 就會將對應(yīng)的錯誤碼,存放在 errno 中,??個錯誤碼的數(shù)字是整數(shù),很難理解是什么意思,所 以每?個錯誤碼都是有對應(yīng)的錯誤信息的。strerror函數(shù)就可以將錯誤碼對應(yīng)的錯誤信息字符串的地 址返回。
參數(shù):
errnum :表示錯誤碼
這個錯誤碼?般傳遞的是 errno 這個變量的值,在C語?有?個全局的變量叫: errno ,當(dāng)庫函數(shù) 的調(diào)?發(fā)?錯誤的時候,就會講本次錯誤的錯誤碼存放在 errno 這個變量中,使?這個全局變量需要 包含?個頭?件 errno.h 。
返回值:
函數(shù)返回通過錯誤碼得到的錯誤信息字符串的?字符的地址。
12.1 代碼演示
#include <errno.h> #include <string.h> #include <stdio.h> //我們打印?下0~10這些錯誤碼對應(yīng)的信息 int main() { int i = 0; for (i = 0; i <= 10; i++) { printf("%d: %s\n", i, strerror(i)); } return 0; }
在Windows11+VS2022環(huán)境下輸出的結(jié)果如下:
0: No error 1: Operation not permitted 2: No such file or directory 3: No such process 4: Interrupted function call 5: Input/output error 6: No such device or address 7: Arg list too long 8: Exec format error 9: Bad file descriptor 10: No child processes
舉例:
#include <stdio.h> #include <string.h> #include <errno.h> int main () { FILE * pFile = NULL; //fopen函數(shù)以讀的形式打開?件,如果?件不存在,則打開失敗。 pFile = fopen ("unexist.ent", "r"); if (pFile == NULL) { printf ("錯誤信息是:%s\n", strerror(errno)); return 1;//錯誤返回 }//讀文件 fclose(pf);//關(guān)閉文件 return 0;//空指針不能解引用 }
輸出:
錯誤信息是:No such file or directory
12.2 perror
也可以了解?下 perror 函數(shù), perror 函數(shù)相當(dāng)于?次將上述代碼中的第11?完成了,直接將錯誤 信息打印出來。 perror 函數(shù)打印完參數(shù)部分的字符串后,再打印?個冒號和?個空格,再打印錯誤 信息。
perror有能力直接打印錯誤信息,打印的時候,先打印傳給perror的字符串,然后打印冒號,再打印空格,最后打印錯誤碼對應(yīng)信息
perrpr=printf+strerror
#include <stdio.h> #include <string.h> #include <errno.h> int main () { FILE * pFile = NULL; pFile = fopen ("unexist.ent", "r"); if (pFile == NULL) { perror("錯誤信息是"); return 1; } return 0; }
輸出:
錯誤信息是: No such file or directory
總結(jié)
到此這篇關(guān)于C/C++字符函數(shù)和字符串函數(shù)的文章就介紹到這了,更多相關(guān)C/C++字符函數(shù)和字符串函數(shù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++基于QWidget和QLabel實現(xiàn)圖片縮放,拉伸與拖拽
這篇文章主要為大家詳細(xì)介紹了C++如何基于QWidget和QLabel實現(xiàn)圖片縮放、拉伸與拖拽等功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-02-02C++實現(xiàn)中綴表達(dá)式轉(zhuǎn)后綴表達(dá)式
這篇文章主要為大家詳細(xì)介紹了C++實現(xiàn)中綴表達(dá)式轉(zhuǎn)后綴表達(dá)式,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2020-04-04