1. 程式人生 > 其它 >字串函式中的求長度、查詢、分割和錯誤報告函式(strlen,strstr,strtok,strerror)

字串函式中的求長度、查詢、分割和錯誤報告函式(strlen,strstr,strtok,strerror)

技術標籤:字串指標c++c語言

文章目錄

一、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: 直接列印錯誤資訊,並且我們可以自己加上註釋來明確錯誤來源於哪個庫函式。