字串函式中的求長度、查詢、分割和錯誤報告函式(strlen,strstr,strtok,strerror)
文章目錄
一、strlen - 求字串長度
1.如何使用
size_t strlen( const char *string );
strlen函式是一個用於求字串長度的庫函式。它的引數是被求長度的字串的起始地址,返回值是一個無符號整型。
注意:
- 引數指向的字串要以’\0’結束。
- strlen返回的是在字串中’\0’之前出現的字元個數(不包含’\0’)。
- 注意函式的返回值為size_t,是無符號的(易錯)。
舉個例子,比如我們要求字串"abcdef"的長度。
#include<stdio.h>
#include<string.h>
int main()
{
char arr[] = "abcdef";
size_t ret = strlen(arr);
return 0;
}
陣列arr的陣列名就是該陣列的起始地址,我們定義一個size_t型的變數ret便能接收函式的返回值,結果是6。
2.模擬實現(三種方式)
方式一:計數器的方式
我們定義一個變數為count,如果傳入的指標指向的內容不是’\0’,那麼count++,同時指標後移一位,迴圈往復,直到找到’\0’時返回count即可。
size_t my_strlen1(const char* str)
{
size_t count = 0;//計數器
while (*str)
{
count++;
str++;
}
return count;
}
方式二:遞迴的方式
我們一進入函式體就判斷傳入指標指向的內容是否為’\0’,如果是就返回0,不是就返回1+my_strlen2(str+1),如此進行下去,直到遞迴到內層時找到’\0’,這時再一步步將值返回回來即可。
size_t my_strlen2(const char* str)
{
if (*str == '\0')
return 0;
else
return 1 + my_strlen2(str + 1);
}
方式三:指標-指標的方式
進入函式體時,我們事先定義一個指標變數將傳入的指標儲存下來,然後將傳入的指標向後移,直到遇到’\0’時,我們返回當前指標與儲存的指標的差值即可。(指標與指標的差的絕對值是兩個指標之間的元素個數)
size_t my_strlen3(const char* str)
{
const char* p = str;//儲存起始位置
while (*str != '\0')
str++;
return str - p;
}
二、strstr - 字串查詢
1.如何使用
char *strstr( const char *string, const char *strCharSet );
strstr函式可以在一個字串(字串1)中查詢另一個字串(字串2),如果字串2存在於該字串1中,那麼就返回被字串2在字串1中第一次出現的起始位置,如果在字串1中找不到字串2,那麼就返回空指標(NULL)。它的第一個引數是字串1的起始位置,第二個引數是字串2的起始位置。
注意:
- 若字串2為空字串,則返回字串1的起始位置。
舉個例子,比如我們在字串"abcdefbcd"中查詢字串"bcd"。
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[] = "abcdefbcd";
char arr2[] = "bcd";
char* ret = strstr(arr1, arr2);//在arr1中查詢arr2字串第一次出現的位置
if (ret != NULL)
printf("%s\n", ret);
else
printf("找不到\n");
return 0;
}
注意:strstr函式的返回值是字串"bcd"在字串"abcdefbcd"中第一次出現的位置的起始位置,而不是出現幾次就返回幾個起始位置。
2.模擬實現
strstr函式的模擬實現相對複雜,在實現過程中我們需要設定3個指標變數來輔助實現函式功能。
cp指標: 記錄每次開始匹配時的起始位置,當從該位置開始匹配時就找到了目標字串,便於返回目標字串出現的起始位置;當從該位置開始沒有匹配成功時,則從cp++處開始下一次的匹配。
p1和p2指標: 通過判斷p1和p2指標解引用後是否相等來判斷每個字元是否匹配成功,若成功,則指標後移比較下一對字元;若失敗,p1指標返回cp指標處,p2指標返回待查詢字串的起始位置。
例如,在字串"abbbcdef"中查詢字串"bbc":
剛剛開始時3個指標的指向如圖所示:
若p1與p2匹配不成功,則cp指標後移,接著將cp指標賦值給p1指標:
此時,p1與p2匹配成功,那麼cp指標不動,p1和p2指標後移繼續比較:
當p1與p2匹配不成功時,cp指標後移一位,p1返回cp位置,p2返回待查詢字串起始位置:
從此位置開始下一輪的比較:
直到當p2指向的內容為\0時,便說明待查詢字串中的字元已經被找完,也說明了從當前cp位置開始匹配能夠找到目標字串,所以此時返回指標cp即可。
char* my_strstr(const char* str1, const char* str2)
{
assert(str1 != NULL);//斷言,當str1為空指標報錯
assert(str2 != NULL);//斷言,當str2為空指標報錯
const char* cp = str1;//記錄開始匹配時的起始位置
if (*str2 == '\0')//要查詢的字串為空字串
return (char*)str1;
while (*cp)
{
const char* p1 = cp;
const char* p2 = str2;
while ((*p1!='\0') && (*p2!='\0') && (*p1 == *p2))
{
p1++;
p2++;
}
if (*p2 == '\0')//目標字串已被查詢完
return (char*)cp;
cp++;
}
return NULL;//找不到目標字串
}
三、strtok - 字串分割
char *strtok( char *strToken, const char *strDelimit );
strtok函式能通過給定的一系列字元將一個字串分割成許多子字串的函式。它的第一個引數是需要被分割的字串的首地址;第二個引數是一個字串的首地址,該字串是用作分隔符的字元集合。返回值是查詢到的標記的首地址。
注意:
- strtok函式找到strToken中的一個標記時,會將其用 \0結尾並返回這個標記的首地址。
- strtok函式會改變strToken函式,所以在使用strtok函式切分的字串都是臨時拷貝的內容並且可修改。
- strtok函式的第一個引數不為NULL時,函式將找到strToken中的第一個標記,並儲存它在字串中的位置。
- strtok函式的第一個引數為NULL時,函式將從同一個字串中被儲存的位置開始查詢它的下一個標記。
- 若字串中不存在更多的標記,則返回NULL指標。
舉個例子,比如我們要將字串"[email protected]"以"@“字元和”."字元分割開。
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[] = "[email protected]";//待分割字串
char arr2[] = "@.";//分隔符的字元集合
char arr3[20] = { 0 };
strcpy(arr3, arr1);//將資料拷貝一份使用,防止原資料被修改
char* token = strtok(arr3, arr2);//第一次傳參需傳入待分割字串首地址
while (token != NULL)//說明還未分割完
{
printf("%s\n", token);
token = strtok(NULL, arr2);//對同一個字串進行分割,第二次及以後的第一個引數為NULL
}
return 0;
}
注意:當strtok函式找到第一個標記時,將其後的’@‘字元改為’\0’並返回第一個標記的首地址,所以我們以返回的地址為首地址開始列印字串的時候就只會打印出2957055542,第二次再對該字串呼叫strtok函式時將從’@'字元後面開始尋找下一個標記。
四、strerror、perror - 錯誤報告函式
1.strerror
char *strerror( int errnum );
strerror函式可以把錯誤碼轉換為對應的錯誤資訊,返回錯誤資訊對應字串的起始地址。
2.perror
void perror( const char *string );
perror函式可以列印一個錯誤資訊,無返回值。
我們需要知道,庫函式在使用的時候如果發生錯誤,都會有對應的錯誤碼,而這些錯誤碼都會被存放在errno這個全域性變數中,如果要使用這個全域性變數,我們需要引其對應的標頭檔案:#include<errno.h>
舉個例子:
注:fopen函式的功能是開啟一個檔案,當其執行成功時會返回開啟檔案的首地址,執行失敗時會返回一個空指標(NULL)。
#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{
FILE* pf = fopen("test.txt", "r");//開啟test.txt檔案閱讀
if (pf == NULL)
{
printf("%s\n", strerror(errno));
perror("fopen");
}
return 0;
}
當我們要開啟一個不存在的檔案(test.txt)來閱讀的時候,顯然fopen函式會執行失敗,於是pf指標接收的便是空指標(NULL)。
strerror: 只負責將錯誤碼轉換為對應的錯誤資訊,不列印。
perror: 直接列印錯誤資訊,並且我們可以自己加上註釋來明確錯誤來源於哪個庫函式。