在編程的過程中,我們經常會遇到需要處理字符和字符串的情況,為了方便操作字符和字符串,C語言標準庫中提供了一系列庫函數,接下來我們就學習一下這些函數。
目錄
1.?字符分類函數
2. 字母轉換函數
3. strlen函數的使用和模擬實現
4. strcpy函數的使用和模擬實現
5. strcat函數的使用和模擬實現
1.?字符分類函數
C語言中有一系列的函數是專門做字符分類的,也就是?個字符是屬于什么類型的字符的。 這些函數的使用都需要包含一個頭文件是<ctype.h>
一共有下面這些函數,當這些函數處理的字符滿足條件時返回值就為真:
iscntrl:任何控制字符
isspace:空白字符:空格' ',換頁符'\f',換行符'\n',回車'\r',制表符'\t'或者垂直制表符'\v'
isdigit:十進制字符'0'~'9'
isxdigit:十六進制字符:包括十進制所有字符,小寫字母a ~ f,大寫字母A~F
islower:小寫字母a~z
isupper:大寫字母A~Z
isalpha:字母a~z或A~Z
isalnum:字母或數字,a~z,A~Z,0~9
ispunct:標點字符,任何不屬于數字或者字母的(可打印)字符
isgraph:任何圖形字符
isprint:任何可打印字符,包括圖形字符和空白字符
這些函數的使用方法非常相似,我們就只列舉一個函數的使用方法:
int islower(int c);
通過返回值來說明是否是小寫字母,如果是小寫字母就返回非0的整數,如果不是小寫字母,則返回0。
例如:將字符串中的小寫字母轉換為大寫字母
#include <ctype.h>
#include <stdio.h>
int main()
{int i = 0;char s[] = "Hello World";while(s[i]){if(islower(s[i]))s[i] -= 32;i++;}printf("%s\n",s);return 0;
}
HELLO WORLD
當返回值為非0值時,將字符的數值減去32,將小寫字母轉換為對應的大寫字母,最后將修改后的字符串打印出來,查看結果是否符合預期。
2. 字母轉換函數
C語言提供了2個字符轉換函數:
int tolower ( int c ); //將參數傳進去的?寫字?轉?寫
int toupper ( int c ); //將參數傳進去的?寫字?轉?寫
上面的代碼中,我們是利用islower函數來判斷字符是否為小寫字母,若是,則讓其減去32,實現小寫字母轉化為大寫字母的效果。而現在,我們可以直接使用toupper函數將小寫字母轉化為大寫字母,例如:
#include <ctype.h>
#include <stdio.h>
int main()
{int i = 0;char s[] = "Hello World";while(s[i]){if(islower(s[i]))s[i] = toupper(s[i]);i++;}printf("%s\n",s);return 0;
}
3. strlen函數的使用和模擬實現
strlen函數原型為:
size_t strlen ( const char * str );
字符串以字符'\0'為結束標志,strlenm函數返回的值是字符串中字符'\0'前的字符個數(不包括'\0')
參數指向的字符串必須要以'\0'結束
注意函數的返回值類型為size_t,是無符號的
strlen的使用需要包含頭文件<string.h>
#include <string.h>
#include <stdio.h>
int main()
{char s[] = "Hello World";printf("%d\n", strlen(s));return 0;
}
11
我們在前面指針的內容中就已經講解過怎么模擬實現strlen函數,這里不再重復:
因為會使用到指針,這里加上assert,防止使用空指針
#include <assert.h>
size_t my_strlen(char* s)
{assert(s);size_t len = 0;while(*s++){len++;}return len;
}
這里再給處一種不創建臨時變量的方法:
int my_strlen(const char * str)
{assert(str);if(*str == '\0')return 0;elsereturn 1+my_strlen(str+1);
}
利用遞歸與指針的方式,在不創建臨時變量的情況下,模擬實現strlen函數,不過這種方法的運行效率比較低,運行會上面的代碼慢
4. strcpy函數的使用和模擬實現
strcpy函數的原型為:
char* strcpy(char * destination, const char * source );
Copies the C string pointed by source into the array pointed by destination, including the terminating null character (and stopping at that point).
簡單來說就是將一個字符串的內容復制到另一個字符串中,進行這個操作要滿足這些條件:
源字符串必須以'\0'結尾。
會將源字符串中的'\0'拷貝到目標空間。
目標空間必須足夠大,以確保能存放源字符串。
目標空間必須可修改。
了解這些后,我們可以嘗試將一個字符串的內容復制到另一個字符串中:
#include <string.h>
#include <stdio.h>
int main()
{char s1[20] = "Hello World";char s2[] = "Good morning";printf("%s\n", strcpy(s1,s2));printf("%s\n",s1);return 0;
}
Good morning
Good morning
了解了使用方法后,我們現在來思考如何模擬實現strcpy函數:
由于C語言自帶的strcpy函數無法檢測目標字符串大小是否能夠放下源字符串內容,我們在模擬實現時加上這一步判斷。
首先,我們要讓函數接收目標字符串dest和源字符串src的地址。
接著,我們要保證傳遞的兩個字符串的地址是有效的,我們要使用assert函數;而且,也要保證字符串dest足夠放下字符串src中的內容,那就需要比較兩個字符串的大小。考慮到目標字符串中可能出現'\0'提前出現的情況,我們不能使用strlen來計算目標字符串的大小,因此,我們需要用sizeof來計算目標字符串大小;相對地,源字符串不需要考慮這個問題,但是字符'\0'也是需要占據空間地,因此在比較時需要讓其+1。但是,由于字符數組dest地址在傳遞給函數時會轉化為數組首元素的地址,在函數內部中使用時只能找到該元素而無法找到整個字符數組,因此在傳遞參數時我們還有額外傳遞參數size_dest,用于比較大小。
然后,我們就需要考慮如何將一個字符串的內容復制到另一個字符串中。
這里我們就要使用指針方法逐個訪問字符串dest和src中的內容,并將src中的內容賦值給dest,直到訪問到src中的'\0'。
最后,返回目標字符串的地址,但是現在有個問題,那就是指針dest指向的地址在我們復制操作結束后已經不是指向dest首字符的地址了。因此,我們需要在賦值前創建一個指針變量來存儲該地址,用于最后返回。
分析完畢,代碼形式如下:
char* my_cpy(char* dest,const char* src,size_t size_dest)
{assert(dest && src);if(size_dest < strlen(src) + 1){printf("目標字符串空間大小不足");return NULL;}char* origin_dest = dest;while((*dest++ = *src++));return origin_dest;
}
我們嘗試使用一下函數my_cpy:
int main()
{char s1[20] = "Hello World";char s2[] = "Good morning";printf("%s\n", my_cpy(s1,s2, sizeof(s1)));printf("%s\n",s1);return 0;
}
Good morning
Good morning
我們可以發現,打印結果符合我們預期,代碼成功模擬實現了strcpy函數的效果。
5. strcat函數的使用和模擬實現
函數strcat原型如下:
char *strcat(char *dest, const char *src);
Appends a copy of the source string to the destination string.
The terminating null character in destination is overwritten by the first character of source,
and a null-character is included at the
end of the new string formed by the concatenation of both in destination
簡單來說就是,將一個字符串的內容追加到另一個字符串的末尾,進行這個操作要滿足這些條件:
源字符串必須以'\0'結束
目標字符串中也得有'\0',否則無法知道從哪里開始追加
目標空間必須有足夠的大,能容納下源字符串的內容。
目標空間必須可修改。
了解這些后,我們可以嘗試使用一下strcat函數:
#include <string.h>
#include <stdio.h>
int main()
{char s1[20] = "Hello ";char s2[] = "World";printf("%s\n", strcat(s1,s2));printf("%s\n",s1);return 0;
}
Hello World
Hello World
我們可以看到,strcat函數成功將字符串s2的內容追加到了字符串s1末尾。
現在,我們來思考一下如何模擬實現strcat函數:
同樣的,由于C語言自帶的strcat函數無法檢測目標字符串大小是否能夠放下源字符串內容,我們在模擬實現時加上這一步判斷。
首先,我們需要函數接收兩個字符串dest和src的地址,以及字符串dest的大小size_dest。
接著,就是相同的操作,檢驗指針的有效性以及字符串dest的空間是否符合要求。若是條件都滿足,創建一個指針變量來存儲dest的地址。
然后,就是追加的操作,這一步和上面my_cpy的操作一樣。只不過我們需要先找到dest中第一個'\0'的位置,然后再開始追加操作。
最后,返回dest的地址。
代碼形式如下:
char* my_cat(char* dest,const char* src,size_t size_dest)
{assert(dest && src);size_t need = strlen(dest) + strlen(src) + 1;if(size_dest < need){printf("目標空間不足,實際需要空間為%zd\n",need);return NULL;}char* origin_dest = dest;while(*dest) dest++;while((*dest++ = *src++));return origin_dest;
}
我們嘗試使用一下函數my_cat:
int main()
{char s1[20] = "Hello ";char s2[] = "World";printf("%s\n", my_cat(s1,s2, sizeof(s1)));printf("%s\n",s1);return 0;
}
Hello World
Hello World
我們可以發現,打印結果符合我們預期,代碼成功模擬實現了strcat函數的效果。