1. 程式人生 > 其它 >C++ <cstring>字串處理函式

C++ <cstring>字串處理函式

技術標籤:學習札記c++字串

字串處理函式包括幾大類可以滿足對char*字串大部分操作,需要包括標頭檔案<cstring>或者<string.h>,選擇幾個仔細研究一下:

#include <iostream>
#include <cstring>
#include <assert.h>
using namespace std;

int strLen(const char *s)
{
	if (NULL==s) throw "Invalid argument";
	//assert(s!=NULL); //或者用<assert.h>庫函式assert() 
    int i;
    //for(;*s!='\0';++s) i++;  
    while(*s++!='\0') i++;  //兩種迴圈都可以 
    
    return i;  
}  

char *strCpy(char *dest,const char *src)  
{
	assert(NULL!=dest);
	assert(NULL!=src); //兩個條件可以用&&合併,但不知錯在哪個條件

    while (*src!='\0'){
   		*dest=*src;
   		dest++;
   		src++;
   	}
 	*dest=*src; //此時等價於*dest='\0'; 
	//while ((*dest++ = *src++)!='\0');  //可合併為一行 

	return dest;
}  

char *strCpy1(char *dest,const char *src)
{
    char *p=dest;
    cout<<"begin copying:"<<endl;
    while (*src!='\0'){
		cout<<*src<<endl;
		*dest++=*src++;
	}
    *dest='\0';
    cout<<"end!"<<endl;
	return p;
}

int main()
{
    int len=0;
    char aChar;
    const char *str = "hello"; // 宣告和賦值 
    //const 不能省,否則有警告提示,但能通過編譯 
	cout<<str<<endl<<endl;

    cout<<"測試:sizeof()、strlen()"<<endl;
	const char msg1[] = "hello,world!hello,world!";
	len = strlen(msg1); //<cstring>庫函式 
	cout<<sizeof(msg1)<<"|"<<len<<endl;  //sizeof 與 strlen 的區別,此時sizeof的值是陣列的大小  
	len = strLen(msg1); //有大寫字母的為自定義函式,以下同 
	cout<<sizeof(msg1)<<"|"<<len<<endl<<endl;

	//定義和賦值分開進行 
	const char *msg;
	msg = "hello,world!hello,world!";
	len = strlen(msg); //<cstring>庫函式 
	cout<<sizeof(msg)<<"|"<<len<<endl;  //此時sizeof的值是指標的大小:64位系統是8;32位系統是4 
	len = strLen(msg); //有大寫字母的為自定義函式,以下同 
	cout<<sizeof(msg)<<"|"<<len<<endl<<endl;
	//結論:sizeof不適合計算字串長度 

    cout<<"測試:移動指標"<<endl;	
	cout<<msg<<endl;
	*msg++;*msg++;	//向後移動指標,對比顯示的內容 
	aChar=*msg;
	cout<<&msg<<endl;  //取地址 
	cout<<*msg<<endl;
	cout<<aChar<<endl<<endl;
	*msg--;*msg--;	//向前移動指標,對比顯示的內容
	aChar=*msg;
	cout<<&msg<<endl;
	cout<<*msg<<endl;
	cout<<aChar<<endl;
	cout<<*(msg+0)<<"="<<msg[0]<<endl;	
	cout<<*(msg+1)<<"="<<msg[1]<<endl;
	cout<<*(msg+2)<<"="<<msg[2]<<endl;	
	cout<<*(msg+3)<<"="<<msg[3]<<endl;
	cout<<*(msg+4)<<"="<<msg[4]<<endl;	
	cout<<*(msg+5)<<"="<<msg[5]<<endl;
	cout<<"["<<*(msg+strlen(msg))<<"]<-NULL/\'0\'"<<endl;
	cout<<msg<<endl<<endl;
	
	cout<<"測試:strcpy()"<<endl;
	for (int i=0;i<12;i++) *msg++; //源字串的長度必須不大於目標字串長度 
	cout<<msg<<endl;
	char dest[21]="ABCDEFGHIJKLMNOPQRST"; //20個字母+'\0' 
	cout<<"["<<dest<<"]:"<<sizeof(dest)<<"|"<<strlen(dest)<<endl;
    strcpy(dest,msg);	//sizeof值未變,strlen值變小 
	cout<<"["<<dest<<"]:"<<sizeof(dest)<<"|"<<strlen(dest)<<endl; 
    strCpy(dest,msg);
	cout<<"["<<dest<<"]:"<<sizeof(dest)<<"|"<<strlen(dest)<<endl; 
    strCpy1(dest,msg);
	cout<<"["<<dest<<"]:"<<sizeof(dest)<<"|"<<strlen(dest)<<endl<<endl; 
	
	cout<<"測試:strncpy()"<<endl;
	char dest1[15]="abcdefghijklmn";
	strncpy(dest1,msg,strlen(msg));
	cout<<dest1<<endl;
	char dest2[10]={0}; //設一個最大長度可為10的空串 
	cout<<dest2<<"|"<<endl;
	strncpy(dest2,msg,strlen(dest2)); //沒複製到內容 
	cout<<dest2<<"|"<<endl;
	strncpy(dest2,msg,sizeof(dest2)); //只能複製到10個字元 
	cout<<dest2<<endl;
	strncpy(dest2,msg,strlen(msg)); //可以得到12個字元,但後2個越界
	cout<<dest2<<"|"<<sizeof(dest2)<<"|"<<strlen(dest2)<<endl;
	
	//結論:dest必須有足夠的空間來容納source的字元長度+'\0';相比strcpy更容易溢位出錯棄用,建議用strncpy
	
	
    return 0;
}

測試結果:

hello

測試:sizeof()、strlen()
25|24
25|24

8|24
8|24

測試:移動指標
hello,world!hello,world!
0x22fe08
l
l

0x22fe08
h
h
h=h
e=e
l=l
l=l
o=o
,=,
[]<-NULL/'\0'
hello,world!hello,world!

測試:strcpy()
hello,world!
[ABCDEFGHIJKLMNOPQRST]:21|20
[hello,world!]:21|12
[hello,world!]:21|12
begin copying:
h
e
l
l
o
,
w
o
r
l
d
!
end!
[hello,world!]:21|12

測試:strncpy()
hello,world!mn
|
|
hello,worl
hello,world!|10|12

--------------------------------
Process exited after 1.042 seconds with return value 0
請按任意鍵繼續. . .

待續......

附錄:

複製函式

char *strcpy(char *s1, const char *s2);
char *strncpy(char *s1, const char *s2, size_t n);
void *memcpy(void *s1, const void *s2, size_t n);
void *memmove(void *s1, const void *s2, size_t n);
  • strcpy,strcpy,memcpy,memmove的第一個引數都為複製的dest,而第二個引數都為複製的源source。
  • strcpy將一個以空字元結尾的字串s2複製給s1
    strncpystrcpy一樣,只不過它限制了複製的字元的個數,最多複製n個字元。如果n過小,那麼strncpy就不能複製末尾的空字元,如果n比源字串長度大,strncpy在遇到空字元後會不斷向目的字串追加空字元,直到達到n個。同時strcpystrncpy在源和目的重疊時也會有問題的。
  • memcpy函式從位元組陣列s2s1複製n個位元組。如果源和目的有重疊,那麼使用memcpy會有問題。memmove函式可以在源和目的重合時正常處理,在其他方面與memcpy相同。
  • memcpymemmovestrncpy函式可用於包括字元在內的任何記憶體塊,而strcpy函式只適合字串,它會持續複製字元,直到遇到源字元中的空字元為止。

拼接函式

char *strcat(char *s1, const char *s2);
char *strncat(char *s1, const char *s2, size_t n);
  • strcat函式將它的第二個引數s2追加到第一個引數s1的末尾。s1s2必須都是以空字元結尾的字串。strcat會用s2的第一個字元覆蓋s1的空字元,並在拼接字串的後邊新增空字元。
  • strncatstrcat功能相同,只是限制了從s2中取出拼接到s1的字元個數。

比較函式

int memcmp(const void *s1, const void *s2, size_t n);
int strcmp(const char *s1, const char *s2);
int strncmp(const char *s1, const char *s2, size_t n);
int stricmp(const char *s1, const char *s2);
int strcoll(const char *s1, const char *s2);
size_t strxfrm(char *s1, const char *s2, size_t n);
  • memcmp,strcmp,strncmp,stricmp函式以指向字元(位元組)陣列的指標為引數,逐個比較兩個字元(位元組)陣列的每個字元。根據比較結束時第一個字元(位元組)陣列中的字元(位元組)是小於、等於或大於第二個字元(位元組)陣列中的字元(位元組)而返回-1,0或1。三個函式的主要區別是在於何時結束比較,如果第一個不同的字元在memcmpstrncmp的範圍n之內,則三者相同。否則,strcmp在遇到空字元停止比較,memcmp不關心空字元,在比較的位元組數達到n個時停止比較,strncmp結合了上述兩個函式的特點,在達到n個字元或遇到空字元時停止比較。
  • stricmp與strcmp功能相似,只不過以大小寫不敏感方式比較。
  • strcrollstrcmp功能相似,只不過比較結果依賴於本地化設定(根據不同的地點比較結果不同)。然而strcoll函式的速度不是很快,當這是個問題或者希望在改變本地設定而不影響比較結果的話,可以使用strxfrm函式,strxfrm將第二個引數進行本地化轉換,並將轉換結果放在第一個引數,引數n限制了轉換的字元個數。

搜尋函式

void *memchr(const void *s, int c, size_t n);
char *strchr(const char *s, int c);
char *strrchr(const char *s, int c);
char *strpbrk(const char *s1, const char *s2);
size_t strcspn(const char *s1, const char *s2); 
size_t strspn(const char *s1, const char *s2);
char *strstr(const char *s1, const char *s2);
char *strtok(char *s1, const char *s2);
  • strchr函式在字串s中搜索字元c,它會返回一個指向s中第一個字元c的指標,如果沒找到,則返回空指標。當遇到空字元時停止搜尋。
  • memchr函式在搜尋了n個字元後停止搜尋,返回第一個字元c的指標,若未找到,則返回空指標。
  • strrchrstrchr類似,只是從字串s的空字元開始,反向搜尋字元c。如果找到,則返回反向第一個字元c的地址,若未找到返回空指標。
  • strpbrk函式從s1中尋找與s2中任意一個字元匹配的第一個字元,並返回指向它的指標。若找不到,則返回空。
  • strspn函式從字串s1中搜索字符集s2,並返回字元組中第一個不屬於給定字符集中的字元的下標,而strcspn函式返回第一個屬於給定字符集中的字元的下標。
  • strstr函式在字串s1中搜索字串s2,返回找到的第一處匹配子串的指標,如果找不到,則返回空。
  • strtok函式在s1中搜索,查詢一個非空字元序列(稱作記號),這個序列不包括s2中指定的字元。將找到的記號後面的那個字元替換為一個空字元標記該記號的末尾,然後返回一個指向該記號的首字元的指標。使用
  • strtok(NULL,s2)就可以繼續上一次的strtok函式呼叫,直到其返回一個空指標為止。

其他函式

void *memset(void *s, int c, size_t n);
size_t strlen(const char *s);
char *strerror(int errnum);
  • memset函式將一個字元的多個副本儲存到指定的記憶體區域。
  • strlen返回字串的長度,不包括字串末尾的空字元。
  • strerror當輸入儲存在errno的錯誤碼時,會返回一個指向描述這種錯誤的字串的指標。