天天看點

C語言 字元串函數

此篇介紹處理字元和字元串的庫函數和注意事項~

字元串

C語言字元串函數的功能非常單一

C語言沒有專門的字元串類型,C語言中字元串類型本質上是一個字元數組。

C字元串的結尾标志是“\0”,字元串本身就帶有一個“\0”。在計算字元串長度時,“\0”是結束标志,不算做字元串内容

以下所有函數使用時,都需包含頭檔案<string.h>

在頭檔案<string.h>中定義了兩組函數。第一組函數的名字以str開頭;第二組函數的名字以mem開頭,本篇隻講str開頭的字元串函數~

字元串函數介紹

1.求字元串長度 strlen

函數原型:

size_t strlen ( const char * str ),

此處的const限制的是位址對應的記憶體空間不能進行修改

從字元串起始位置開始向後找,找到’\0’就結束,傳回該C字元串的長度

strlen的注意事項

1.參數指向的字元串必須以 ’ \0 ‘結束

2.size_t是無符号類型的整數,在标準庫中用來表示"個數",在進行size_t進行相減時,特别容易溢出,故一般不适用size_t.

3.strlen函數傳回的是在字元串中 ‘\0’ 前面出現的字元個數(不包含 ‘\0’ )

4.使用strlen必須是字元串才可以

代碼實作

size_t myStrlen(const char* str) {
	//校驗參數合法性
	assert(str != NULL);
	size_t count = 0;
	while (str[count] != '\0') {
		count++;
	}
	return count;
}
           

2.字元串拷貝 strcpy(比較麻煩)

函數原型:

char * strcpy ( char * destination, const char * source )

strcpy的注意事項:

1.source參數必須是字元串

2.destination參數空間必須足夠大,能夠容納下source,或者使用strncpy來取代

3.将source指向的C字元串複制到destination指向的數組中,包括終止空字元(’\0’),最後傳回destination

代碼實作

char* myStrcpy(char* dest, const char* source) {
	//校驗參數合法性
	assert(dest != NULL);
	assert(source != NULL);
	int i = 0;
	while (source[i] != '\0') {
		dest[i] = source[i];
		i++;
	}
	dest[i] = '\0';
	return dest;
}
           

3. 字元串拼接 strcat(比較麻煩)

函數原型:

char * strcat ( char * destination, const char * source )

strcat的注意事項:

1.目的地和來源不得重疊

2.destination的空間要足夠大,能夠容下拼接後的結果

3.destination最後的結束字元’\0’會被覆寫掉,并在連接配接後的字元串的尾部再增加一個’\0’

char dest[ ]=“hello”

char source[ ]=“world”

C語言 字元串函數

将源字元串拷貝追加(尾部增加)到目标字元串。destination 中的’\0’被source的第一個字元覆寫,并且在由destination 中的兩者連接配接形成的新字元串的末尾包含一個空字元,最後傳回destination

代碼實作

char* myStrcat(char* dest, const char* source) {
	//校驗參數合法性
	assert(dest != NULL);
	assert(source != NULL);
	//1.找到dest的結束位置
	int destEnd = 0;
	while (dest[destEnd] != '\0') {
		destEnd++;
	}
	//while循環結束,下标為destEnd的dest便指向\0
	//2.字元串拷貝
	int i = 0;
	while (source[i] != '\0') {
		dest[i + destEnd] = source[i];
		i++;
	}
	//3.把dest的最後位置設成\0
	dest[i + destEnd] = '\0';
	return dest;
}
           

4. 字元串比較 strcmp

函數原型:

int strcmp ( const char * str1, const char * str2 )

https://blog.csdn.net/m0_47988201/article/details/117201616?spm=1001.2014.3001.5501.

此篇文章的最後部分對strcmp進行了說明

代碼實作

int myStrcmp(const char* str1, const char* str2) {
	//校驗參數合法性
	assert(str1 != NULL);
	assert(str2 != NULL);
	const char* p1 = str1;
	const char* p2 = str2;
	//依次比較每個字元
	while (*p1 !='\0'&& *p2 !='\0') {
		if (*p1 < *p2) {
			return -1;
		}
		else if (*p1 > *p2) {
			return 1;
		}
		//相等時比較下一個字元
		else {
			p1++;
			p2++;
		}
	}
	if (*p1 < *p2) {
		return -1;
	}
	else if (*p1 > *p2) {
		return 1;
	}
	else {
		return 0;
	}
}
           

5.拷貝指定長度字元串 strncpy(比較麻煩)

函數原型:

char * strncpy ( char * destination, const char * source, size_t num )

strncpy誕生的目的是為了避免出現dest空間不夠的情況

将source的前num個字元拷貝到destination

strncpy注意事項

1.當num比source長的時候,拷貝完源字元串之後,在目标的後邊追加0,直到num個

2.當num比source短的時候,就隻拷貝source的前num個字元(不會拷貝\0)

3.num的數值,必須要保證dest能夠容納下(需考慮\0)

4.source和destination所指的記憶體區域不能重疊,且destination必須有足夠的空間放置num個字元

無論觸發strncpy的那種情況,都建議把dest初始化為全0,防止出現沒有\0的情況

一般把num寫成sizeof(dest)-1

代碼實作

char* myStrncpy(char* dest, const char* source, size_t num) {
	//校驗參數合法性
	assert(dest != NULL);
	assert(source != NULL);
	assert(num != 0);
	int i = 0;
	while (source[i] != '\0' && i < num) {
		dest[i] = source[i];
		i++;
	}
	while (i < num) {
		dest[i] = '\0';
		i++;
	}
	return dest;
}
           

6.追加指定長度字元串 strncat(比較麻煩)

函數原型:

char * strncat ( char * destination, const char * source, size_t num )

将source的前num 個字元追加到destination,再加上一個\0. 如果source 中C字元串的長度小于num,則隻複制\0之前的内容。

strncat注意事項

1.destination要有足夠大的空間來容納要拷貝的字元串

2.如果num大于字元串source的長度,那麼僅将source全部追加到destination的尾部

3.strncat會将destination字元串最後的’\0’覆寫掉,字元追加完成後,再追加’\0’

代碼實作

char* myStrncat(char* dest, const char* source, size_t num) {
	//校驗參數合法性
	assert(dest != NULL);
	assert(source != NULL);
	assert(num != 0);
	//1.先找到dest的末尾位置
	size_t destEnd = 0;
	while (dest[destEnd] != '\0') {
		destEnd++;
	}
	size_t i = 0;
	while (source[i] != '\0'&& i < num) {
		dest[destEnd + i] = source[i];
		i++;
	}
	dest[destEnd + i] = '\0';
	return dest;
}
           

7. 比較指定長度字元串 strncmp

函數原型:

int strncmp ( const char * str1, const char * str2, size_t num )

比較str1和str2的前num個字元

比較規則遵循字典序

代碼實作

int myStrncmp(const char* str1, const char* str2, size_t num) {
	//校驗參數合法性
	assert(str1 != NULL);
	assert(str2 != NULL);
	assert(num != 0);
	size_t i = 0;
	while (str1[i] != '\0' && str2[i] != '\0' && i < num) {
		if (str1[i] < str2[i]) {
			return -1;
		}
		else if (str1[i] > str2[i]) {
			return 1;
		}
		else {
			i++;
		}
	}
	if (i == num) {
		return 0;
	}
	return str1[i] - str2[i];
}
           

8. 查找字元串 strstr

函數原型:

const char * strstr ( const char * str1, const char * str2 )

判斷一個字元串是否包含另一個字元串(字元串子串)

舉例:

str1:helloworld

str2:llo

比較str1是否包含str2

分析過程:

C語言 字元串函數

代碼實作

const char* myStrstr(const char* str1, const char* str2) {
	//校驗參數合法性
	assert(str1 != NULL);
	assert(str2 != NULL);
	assert(*str1 != '\0');
	assert(*str2 != '\0');
	//建立指針black和sub,分别指向str1和str2的起始位置
	const char* black = str1;
	const char* sub = str2;
	while (*black != '\0') {
		const char* tmp = black;
		//每次比對未成功就要從起始位置從新比對
		char* sub = str2;
		//比較結束的條件:black和sub指針當中有任意一個已經到達了\0 處
		while (*sub != '\0' && *tmp != '\0') {
			//若相等,sub和tmp繼續向後比較
			if (*tmp == *sub) {
				sub++;
				tmp++;
			}
			//不相等,直接跳出目前循環
			else {
				break;
			}
		}
		if (*sub == '\0') {
			return black;
		}
		//比對未成功,從下一位置繼續進行比較
		black++;
	}
	return NULL;
}
           

9. 字元串切分 strtok

函數原型:

char * strtok ( char * str, const char * delimiters )

此函數需多次調用

對此函數的調用序列将str拆分為标記,這些标記是由作為delimiters一部分的任何字元分隔的連續字元序列

舉例:

str為 aaa bbb ccc

  1. 第一次調用:strtok(str," “)

    從str起始位置開始,向後找” “,當遇到” “時,就傳回第一個aaa,同時把剛才的” "改成’\0’

  2. 第二次調用:strtok(NULL," “)

    此時第一個參數為NULL,表示從上次的切分結果位置繼續往下切分~當找到bbb後面的” “時,仍然把” "改成’\0’,并且傳回bbb

  3. 第三次調用:strtok(NULL," “)

    第一個參數仍為NULL,繼續從上次的結束位置繼續往下切分,沒找到” ",找到ddd後的’\0’,函數傳回ddd

  4. 第四次調用:strtok(NULL," ")

    第一個參數仍為NULL,繼續從上次的結束位置繼續往下切分,上次結束位置後沒有東西了,即找完了,說明整個字元串切分完畢,此時直接傳回NULL

代碼實作

char str[] = "aaa bbb ccc";
   char* pch = strtok(str, " ");
   while (pch != NULL) {
   	printf("%s\n", pch);
   	pch = strtok(NULL, " ");
   }
           

strtok的缺點:

1.需要多次調用才能完成功能;

2.多次調用的過程中參數不同;

3.調用過程中會破壞原來的字元串;

4.strtok内部使用靜态變量記錄上次調用的位置,導緻線程不安全;

故實際開發中不建議使用strtok

參考文檔: http://cplusplus.com/.

繼續閱讀