可以做360度全景圖的網(wǎng)站打開百度網(wǎng)站
前言
今天這篇博客咱們一起來認識一些特殊的函數(shù),在編程的過程中,我們經(jīng)常要處理字符和字符串,為了方便字符和字符串,C語言提供了一些庫函數(shù),讓我們一起看看這些函數(shù)都有什么功能吧!!!
個人主頁:小張同學zkf
若有問題 評論區(qū)見
感興趣就關(guān)注一下吧
目錄
?1. 字符分類函數(shù)
2. 字符轉(zhuǎn)換函數(shù)
3. strlen的使用和模擬實現(xiàn)
4. strcpy的使用和模擬實現(xiàn)
5. strcat的使用和模擬實現(xiàn)
?6. strcmp的使用和模擬實現(xiàn)
?7. strncpy,strncat,?strncmp函數(shù)的使用
8. strstr的使用和模擬實現(xiàn)
9. strtok函數(shù)的使用
10.strerror函數(shù)的使用
1. 字符分類函數(shù)
C語言中有一系列的函數(shù)是專門做字符分類的,也就是一個字符是屬于什么類型的字符的。
這些函數(shù)的使用都需要包含一個頭文件是 <ctype.h>
?以上函數(shù)使用方法非常類似,我們隨便列舉一個,結(jié)構(gòu)都非常相似
int islower ( int c );
?islower 是能夠判斷參數(shù)部分的 c 是否是小寫字母的。
通過返回值來說明是否是小寫字母,如果是小寫字母就返回非0的整數(shù),如果不是小寫字母,則返回0。其他分類函數(shù)跟這個一樣,滿足對應條件返回非0整數(shù),不滿足條件,返回0,記住非0的整數(shù)不一定是1!!!
2. 字符轉(zhuǎn)換函數(shù)
?
C語言提供了2個字符轉(zhuǎn)換函數(shù):
?
int tolower ( int c ); //將參數(shù)傳進去的大寫字母轉(zhuǎn)小寫
int toupper ( int c ); //將參數(shù)傳進去的小寫字母轉(zhuǎn)大寫
這兩個函數(shù)的功能相當于對應字符ASC碼值加減32來轉(zhuǎn)換大小寫嘛
從這個函數(shù)開始以下所有的函數(shù)以str開頭的都是字符串函數(shù),頭文件<string.h>
3. strlen的使用和模擬實現(xiàn)
?
格式
size_t strlen ( const char * str );
這個已經(jīng)很熟悉,之前博客無數(shù)次提到,它就是字符串函數(shù)其中之一strlen函數(shù)
注意幾個事項:
? 字符串以 '\0' 作為結(jié)束標志,strlen函數(shù)返回的是在字符串中 '\0' 前面出現(xiàn)的字符個數(shù)(不包
含 '\0' )。
? 參數(shù)指向的字符串必須要以 '\0' 結(jié)束。
? 注意函數(shù)的返回值為size_t,是無符號的( 易錯 )
? strlen的使用需要包含頭文件
我們來再看看strlen用法
看以下代碼:
#include <stdio.h>
#include <string.h>
int main()
{
const char* str1 = "abcdef";
const char* str2 = "bbb";
if(strlen(str2)-strlen(str1)>0)
{
printf("str2>str1\n");
}
else
{
printf("srt1>str2\n");
}
return 0;
}
通俗的說,strlen就是計算字符串中‘\0’之前字符個數(shù)
我們既然知道這個函數(shù)的功能,那怎么樣模仿它實現(xiàn)呢
方法一:
我們分析一下,我們可以創(chuàng)建一個計數(shù)變量count,只要傳過去的指針解引用滿足不為‘\0’字符,那么count就++
以下是我創(chuàng)建的函數(shù)來模擬strlen的實現(xiàn)
//計數(shù)器方式
int my_strlen(const char * str)
{
int count = 0;
assert(str);//防止傳來的函數(shù)指針是野指針,可以斷言一下
while(*str)
{
count++;
str++;
}
return count;
}
?
方法二:
假如規(guī)定我們不創(chuàng)建臨時變量,我們該怎么做哪,我們不如用函數(shù)遞歸的思想看可行不可行
用函數(shù)遞歸的方法,將它大事化小,一個字符一個字符的分離加上去,就像橘子那樣一片一片的往外剝
看一下代碼
//不能創(chuàng)建臨時變量計數(shù)器
int my_strlen(const char * str)
{
assert(str);
if(*str == '\0')
return 0;
else
return 1+my_strlen(str+1);
}
方法三:
我們還可以用指針運算來模仿strlen函數(shù),指針-指針求得偏移量就是字符個數(shù)
看下代碼
//指針-指針的方式
int my_strlen(char *s)
{
assert(str);
char *p = s;
while(*p != ‘\0’ )
p++;
return p-s;
}
4. strcpy的使用和模擬實現(xiàn)
char* strcpy(char * destination, const char * source );
這個strcpy函數(shù)功能是將第二個參數(shù)字符串拷貝一份到第一個參數(shù),使第一個參數(shù)字符串與第二個參數(shù)字符串相同
注意:? 源字符串必須以 '\0' 結(jié)束。
? 會將源字符串中的 '\0' 拷貝到目標空間。
? 目標空間必須足夠大,以確保能存放源字符串。
? 目標空間必須可修改。
?
我們來模擬實現(xiàn)一下這個函數(shù)
我們分析一下,簡單來說,它不就是將第二個參數(shù)字符串中的字符挨個給第一個參數(shù)字符串中的字符賦值嘛,那我可以把他們分別解引用,賦完值地址再加加再解引用……循環(huán)下去直到把‘\0’也賦值過去停止
以下是模擬這個函數(shù)的代碼
char* my_strcpy(char *dest, const char*src)
{
char *ret = dest;
assert(dest != NULL);
assert(src != NULL);
while((*dest++ = *src++))
{
;
}
return ret;
}
?
5. strcat的使用和模擬實現(xiàn)
char* strcat(char * destination, const char * source );
strcat這個函數(shù)就是追加的意思,將第二個參數(shù)的字符串追加到第一個參數(shù)的字符串的后面。
注意:
? 源字符串必須以 '\0' 結(jié)束。
? 目標字符串中也得有 \0 ,否則沒辦法知道追加從哪里開始。
? 目標空間必須有足夠的大,能容納下源字符串的內(nèi)容。
? 目標空間必須可修改
接下來模擬一下這個函數(shù)
我們仔細想,可以把它拆成兩部分先將目標字符串的指針指向‘\0’,再將要追加的函數(shù)從這里進行拷貝
以下是模擬實現(xiàn)這個函數(shù)的代碼
char *my_strcat(char *dest, const char*src)
{
char *ret = dest;
assert(dest != NULL);
assert(src != NULL);
while(*dest)
{
dest++;
}\\找'\0'
while((*dest++ = *src++))\\開始拷貝
{
;
}
return ret;
}
?
我們假想一下,一個字符串能自己追加自己嗎
字符串要是自己追加自己,它原函數(shù)的“\0”被覆蓋了,你追加函數(shù)是它本身,也沒“\0”了,所以沒"\0"它會死循環(huán)追加下去!!!
?6. strcmp的使用和模擬實現(xiàn)
int strcmp (const char * str1, const char * str2)
看這個函數(shù)的格式,我們要知道它的返回值是整形
這個函數(shù)就是讓字符串進行比較,若第一個參數(shù)的字符串大于第二個參數(shù)的字符串,返回大于零的數(shù),若第一個參數(shù)的字符串小于第二個參數(shù)的字符串,返回小于零的數(shù),若相等,返回零,比較的話這兩個指針指向的字符串不能變,所以都得用const修飾
那倆字符串具體怎么比較那
就是將他們所有字符asc碼值一個一個字符對應比較,直到比較出結(jié)果不再比較,‘\0’asc碼值比任何字符都小
我們來模擬實現(xiàn)一下這個函數(shù)
這個函數(shù)簡單來說就是每個字符比較唄,那我就分別解引用比較若相等,再地址加加,循環(huán)下去,若字符一直相同直到‘\0’還相同,那就返回零代表倆字符相等,若加加過程中,突然字符不相等,那就跳出這個循環(huán),直接返回現(xiàn)在所指的字符之差的數(shù)。
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;
}
?7. strncpy,strncat,strncmp函數(shù)的使用
這三個跟上面的比肉眼可見多了個n,其實就是有個數(shù)限制了
怎么說那
就拿這個strncpy來說
char * strncpy ( char * destination, const char * source, size_t num );
發(fā)現(xiàn)多了個參數(shù)num,這個num的意思就是我要拷貝幾個字符過去,就是這意思,拷貝幾個就是幾個,不帶‘\0’拷貝過去,除非它將字符串全拷貝過去帶上‘\0’
那strncat,strncmp也是這個意思,我要追加幾個,比較幾個
注意的是strncat不管追加幾個都會自動再追加個‘\0‘,畢竟追加過后的字符串末尾也得有‘\0’呀
8. strstr的使用和模擬實現(xiàn)
char * strstr ( const char * str1, const char * str2);
這個就是在str1中找到str2的字符串,返回的是字符串str2在字符串str1中第?次出現(xiàn)的位置
strstr模擬實現(xiàn):
這個我們先想如果我們找到了對應的第一個字符相同那我們是不是先用一個指針記錄下來,假如后面也都相同那不就找到這個函數(shù)的位置了嘛,那返回是不是返回位置相同的起始位置,那就是需要記錄起始位置的指針,接下來我們再想想找到了第一個相同的字符,接下來肯定需要指針繼續(xù)往后指進行判斷,若中間字符不相同了,那相同的起始位置的指針向后移找到下一個相同的起始位置,從而形成循環(huán),那我是不是又要需要兩個指針那,這兩個指針分別從相同的起始位置往后移進行比較,所以我們需要創(chuàng)建三個指針,還要記住比較過程中,若中間有一個字符串指向‘\0’,那跳出循環(huán),若是第二個參數(shù)字符串先到‘\0’,那就是找到了,返回初始相同位置的指針,若第一個參數(shù)字符串都指向‘\0’,而第二個字符串還沒有指向‘\0’,那就是沒找到。
char * strstr (const char * str1, const char * str2)
{
char *cp = (char *) str1;
char *s1, *s2;
if ( !*str2 )
return((char *)str1);
while (*cp)
{
s1 = cp;
s2 = (char *) str2;
while ( *s1 && *s2 && !(*s1-*s2) )
s1++, s2++;
if (!*s2)
return(cp);
cp++;
}
return(NULL);
}
9. strtok函數(shù)的使用
char * strtok ( char * str, const char * sep);
這個函數(shù)就是分隔符將字符串分割起來,返回的指針就是這個分隔符標記的指針
哈哈什么意思那
分隔符就是一些特殊符號比如@……這個第二個參數(shù)里面存儲的字符串就是第一個參數(shù)的字符串里特殊符號的集合,就是分隔符的集合
注意:
? sep參數(shù)指向一個字符串,定義了用作分隔符的字符集合
? 第一個參數(shù)指定一個字符串,它包含了0個或者多個由sep字符串中一個或者多個分隔符分割的標
記。
? strtok函數(shù)找到str中的下一個標記,并將其用?\0 結(jié)尾,返回一個指向這個標記的指針。(注:
strtok函數(shù)會改變被操作的字符串,所以在使?strtok函數(shù)切分的字符串?般都是臨時拷貝的內(nèi)容
并且可修改。)
? strtok函數(shù)的第一個參數(shù)不為 NULL ,函數(shù)將找到str中第一個標記,strtok函數(shù)將保存它在字符串
中的位置。
? strtok函數(shù)的第一個參數(shù)為 NULL ,函數(shù)將在同一個字符串中被保存的位置開始,查找下一個標
記。
? 如果字符串中不存在更多的標記,則返回 NULL 指針。
我們來看一個奇妙的代碼加深理解
#include <stdio.h>
#include <string.h>
int main()
{
char arr[] = "192.168.6.111";
char* sep = ".";
char* str = NULL;
for (str = strtok(arr, sep); str != NULL; str = strtok(NULL, sep))
{
printf("%s\n", str);
}
return 0;
}
大家看看這個for循環(huán),初始值就是第一個標記之前的字符串,然后保存這個標記的位置,然后從這個標記的位置開始找到下一個標記,打印這個保存的標記到下一個標記之間的字符串,然后保存下一個標記……直到一個標記為空指針,循環(huán)結(jié)束
10.strerror函數(shù)的使用
char * strerror ( int errnum );
strerror函數(shù)可以把參數(shù)部分錯誤碼對應的錯誤信息的字符串地址返回來。
在不同的系統(tǒng)和C語言標準庫的實現(xiàn)中都規(guī)定了一些錯誤碼,一般是放在 errno.h 這個頭文件中說明的,C語言程序啟動的時候就會使用一個全局的變量errno來記錄程序的當前錯誤碼,只不過程序啟動的時候errno是0,表示沒有錯誤,當我們在使用標準庫中的函數(shù)的時候發(fā)生了某種錯誤,就會將對應的錯誤碼,存放在errno中,而一個錯誤碼的數(shù)字是整數(shù)很難理解是什么意思,所以每一個錯誤碼都是有對應的錯誤信息的。strerror函數(shù)就可以將錯誤對應的錯誤信息字符串的地址返回。
?
#include <errno.h>
#include <string.h>
#include <stdio.h>
//我們打印?下0~10這些錯誤碼對應的信息
int main()
{
int i = 0;
for (i = 0; i <= 10; i++) {
printf("%s\n", strerror(i));
}
return 0;
}
結(jié)果
也可以了解一下perror函數(shù),可以直接將錯誤信息打印出來。perror函數(shù)打印完參數(shù)部分的字符串后,再打印一個冒號和一個空格,再打印錯誤信息。
?舉個例子
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main ()
{
FILE * pFile;
pFile = fopen ("unexist.ent","r");
if (pFile == NULL)
perror("Error opening file unexist.ent");
return 0;
}
輸出
?Error opening file unexist.ent: No such file or directory
OK字符串函數(shù)與字符函數(shù)總結(jié)結(jié)束,下篇總結(jié)一些內(nèi)存函數(shù)